12

I am after a regular expression that validates a percentage from 0 100 and allows two decimal places.

Does anyone know how to do this or know of good web site that has example of common regular expressions used for client side validation in javascript?

@Tom - Thanks for the questions. Ideally there would be no leading 0's or other trailing characters.

Thanks to all those who have replied so far. I have found the comments really interesting.

Joel Cunningham
  • 13,620
  • 8
  • 43
  • 49

11 Answers11

33

Rather than using regular expressions for this, I would simply convert the user's entered number to a floating point value, and then check for the range you want (0 to 100). Trying to do numeric range validation with regular expressions is almost always the wrong tool for the job.

var x = parseFloat(str);
if (isNaN(x) || x < 0 || x > 100) {
    // value is out of range
}
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • It seems, writing correct regex is often like solving a puzzle - unnecessary but challenging. – Alexander Prokofyev Oct 23 '08 at 05:58
  • Good, it doesn't check whenever x have more than 2 decimal, is was trivial to check it, something like this: var decSeparator="."; if((""+x).indexOf(decSeparator) – kentaromiura Oct 23 '08 at 07:20
  • mmm, sorry in the code posted above i forgot a piece XD, the correct example is: var decimalSeparator=".",val=""+x; if(val.indexOf(decimalSeparator) – kentaromiura Oct 23 '08 at 07:25
  • Of course you may need to remove the percent sign if that is allowed in the text field. I used this logic, but determined whether it had a percentage sign, then removed it, then did the test, then added it back in if it was there originally. – John Pasquet Aug 01 '17 at 13:18
17

I propose this one:

(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)

It matches 100, 100.0 and 100.00 using this part

^100(\.0{1,2})?$

and numbers like 0, 15, 99, 3.1, 21.67 using

^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$

Note what leading zeros are prohibited, but trailing zeros are allowed (though no more than two decimal places).

Alexander Prokofyev
  • 33,874
  • 33
  • 95
  • 118
5

This reminds me of an old blog Entry By Alex Papadimoulis (of The Daily WTF fame) where he tells the following story:

"A client has asked me to build and install a custom shelving system. I'm at the point where I need to nail it, but I'm not sure what to use to pound the nails in. Should I use an old shoe or a glass bottle?"

How would you answer the question?

  1. It depends. If you are looking to pound a small (20lb) nail in something like drywall, you'll find it much easier to use the bottle, especially if the shoe is dirty. However, if you are trying to drive a heavy nail into some wood, go with the shoe: the bottle with shatter in your hand.

  2. There is something fundamentally wrong with the way you are building; you need to use real tools. Yes, it may involve a trip to the toolbox (or even to the hardware store), but doing it the right way is going to save a lot of time, money, and aggravation through the lifecycle of your product. You need to stop building things for money until you understand the basics of construction.

This is such a question where most people sees it as a challenge to come up with the correct regular expression to solve the problem, but it would be much better to just say that using regular expressions are using the wrong tool for the job.

The problem when trying to use regex to validate numeric ranges is that it is hard to change if the requirements for the allowed range is changes. Today the requirement may be to validate numbers between 0 and 100 and it is possible to write a regex for that which doesn't make your eyes bleed. But next week the requirment maybe changes so values between 0 and 315 are allowed. Good luck altering your regex.

The solution given by Greg Hewgill is probably better - even though it would validate "99fxx" as "99". But given the circumstances that might actually be ok.

Community
  • 1
  • 1
mlarsen
  • 4,617
  • 1
  • 20
  • 17
2
^100(\.(0){0,2})?$|^([1-9]?[0-9])(\.(\d{0,2}))?\%$

This would match:
100.00
optional "1-9" followed by a digit (this makes the int part), optionally followed by a dot and two digits


From what I see, Greg Hewgill's example doesn't really work that well because parseFloat('15x') would simply return 15 which would match the 0<x<100 condition. Using parseFloat is clearly wrong because it doesn't validate the percentage value, it tries to force a validation. Some people around here are complaining about leading zeroes and some are ignoring trailing invalid characters. Maybe the author of the question should edit it and make clear what he needs.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Tom
  • 6,991
  • 13
  • 60
  • 78
1

Given that your value is in str

str.match(/^(100(\.0{1,2})?|([0-9]?[0-9](\.[0-9]{1,2})))$/)
Czimi
  • 2,494
  • 17
  • 14
1

I recomend this, if you are not exclusively developing for english speaking users:

[0-9]{1,2}((,|\.)[0-9]{1,10})?%?

You can simply replace the 10 by a 2 to get two decimal places.

My example will match:

15.5
5.4366%
1,43
50,55%
34
45%

Of cause the output of this one is harder to cast, but something like this will do (Java Code):

private static Double getMyVal(String myVal) {
    if (myVal.contains("%")) {
        myVal = myVal.replace("%", "");
    }
    if (myVal.contains(",")) {
        myVal = myVal.replace(',', '.');
    }
    return Double.valueOf(myVal);
}
1

None of the above solutions worked for me, as I needed my regex to allow for values with numbers and a decimal while the user is typing ex: '18.'

This solution allows for an empty string so the user can delete their entire input, and accounts for the other rules articulated above.

/(^$)|(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)\.(\.[0-9]{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)/

0

(100|[0-9]{1,2})(\.[0-9]{1,2})?

That should be the regex you want. I suggest you to read Mastering Regular Expression and download RegexBuddy or The Regex Coach.

nickf
  • 537,072
  • 198
  • 649
  • 721
Julien Grenier
  • 3,364
  • 2
  • 30
  • 43
0

@mlarsen: Is not that a regex here won't do the job better.

Remember that validation msut be done both on client and on server side, so something like:

100|(([1-9][0-9])|[0-9])(\.(([0-9][1-9])|[1-9]))?

would be a cross-language check, just beware of checking the input length with the output match length.

kentaromiura
  • 6,459
  • 2
  • 21
  • 15
  • And now you have a regex which matches this requirement. A week later the requirements changes so now your regex should match values between 0 and 255 instead. Good luck changing your regex and have it readable afterwards. – mlarsen Oct 24 '08 at 06:27
  • Yes, It's true, good point here, but in either case there are downside, so is just a matter of what you want to do... You see, I use to put regex in the configuration file, so if a requirement change, I already know where to modify the validation code. – kentaromiura Oct 24 '08 at 16:56
0
(100(\.(0){1,2})?|([1-9]{1}|[0-9]{2})(\.[0-9]{1,2})?)
Bugs
  • 4,491
  • 9
  • 32
  • 41
  • 1
    Can your add more details to explain how your regex solve the problem ? – Guillaume S Sep 04 '18 at 07:34
  • While this might answer the authors question, it lacks some explaining words and links to documentation. Raw code snippets are not very helpful without some phrases around it. You may also find [how to write a good answer](https://stackoverflow.com/help/how-to-answer) very helpful. Please edit your answer. – hellow Sep 04 '18 at 09:15
0

This \(\d{1,3}%\)|\d{1,3}% or /\(\d{1,3}%\)|\d{1,3}% ?/g will match the following cases;

  • 100% - Percentage with three digits
  • (100%) - Three digits percentage within parenthesis
  • 10% - Percentage with two digits
  • (10%) - Two digits percentage within parenthesis
  • 0% - Percentage with one digit
  • (0%) - One digit percentage within parenthesis
mapmalith
  • 1,303
  • 21
  • 38