18

I have this REGEX almost perfect ... It seems to handle everything except a number that leads with a negative sign and then a decimal. So if I enter:

-.2

I get an error -

Here is my Regex -- everything else I've tested works perfectly...

^(\+|-)?[0-9]{1,11}?(?:\.[0-9]{1,4})?$

This allows for:

  • a number up to 11 digits (99 Billion)
  • positive or negative number
  • up to 4 decimal places (optional)
  • leading 0 before decimal point is optional - for positive numbers only

These all work:

-0.2345
-10
12
.125
0.1245
5.555
25000000000 (aka 25 Billion)
25000000000.25 

These do not work:

-.2
-.421
rae1
  • 6,066
  • 4
  • 27
  • 48
Danimal111
  • 1,976
  • 25
  • 31
  • @JohnBupit - `.125` is in his list of things that work – Hogan Apr 28 '14 at 20:33
  • But it mustn't: `".125".match(/^(\+|-)?[0-9]{1,11}?(?:\.[0-9]{1,4})?$/)` – John Bupit Apr 28 '14 at 20:35
  • another bug? should `100000000000.0001` be legal? – Hogan Apr 28 '14 at 20:41
  • @Hogan - No ... I don't want it to go over 100 Billion. Thanks to all... someone posted the following then deleted it... (and it seems to work perfectly!! Thanks to the mystery helper. I put it in production and moved on to my next issue... thanks to all for the quick and brilliant responses!!: ^(\+|-)?\.?[0-9]{1,11}?(?:\.[0-9]{1,4})?$ – Danimal111 Apr 28 '14 at 20:46
  • @DanB - That answer is wrong, it will allow illegal numbers like `.2.2` that is why he deleted it (my comment). Please use John's answer or my answer. They still won't limit to less than 100 Billion but they are better. – Hogan Apr 28 '14 at 20:51
  • Thank you Hogan!!! Updating production now... Much appreciated. – Danimal111 Apr 28 '14 at 20:56

6 Answers6

20

Regex can be expensive... Why not use Decimal.Parse or Float.parse?

Your current implementation would never work with alternate number styles, like European where . (dot) and , (comma) are interchanged ...whereas Decimal.Parse will:

string stringValue = "45.889,33";
CultureInfo currentCulture = Thread.CurrentCulture; //set this way up in the execution chain
decimal thenumber = Decimal.Parse(stringValue, currentCulture);
//thenumber = 45889.33 in us-en display format.

Numerical parsing is not a good application for regex, IMO.

enorl76
  • 2,562
  • 1
  • 25
  • 38
  • 2
    Your answer is also a lot easier to understand than the Regex ones - and hence the code will be easier to maintain – Paul Richards Apr 29 '14 at 08:51
  • @enorl76 - What would happen if the user entered 45,889.33 and then I used the "Decimal.Parse(stringValue, french_culture);" wouldn't it gen an error in that case?? Would I need something like Decimal.TryParse() at that point?? (I'm not concerned with this being used in Europe in this instance, but want to know for my own edification. – Danimal111 Apr 29 '14 at 14:35
  • @DanB: if the current culture is en-US, then the user's input would be properly input. if the current culture is fr-FR, then "45.889,33" would also be properly input. If you want "validation" then yes, Decimal.TryParse would inform you of validity, with respect to the current culture's NumericalFormat specifications. – enorl76 Apr 29 '14 at 14:40
9

Try this:

^(\+|-)?[0-9]{0,11}?(?:\.[0-9]{1,4})?$

Update:

The above regex accepts strings +, - and (the empty string). You can use a lookahead to restrict those. The lookahead ensures there must be a character after the + or - sign.

The correct solution is:

^(\+|-)?(?=.{1})[0-9]{0,11}(?:\.[0-9]{1,4})?$

A working example:

Strings accepted:

-0.2345
-10
12
.125
0.1245
5.555
-.2
-.421

Strings not accepted:

100000000000.0001
+
-

123456789012
1111111111.12345
+1.11.1
-2.
John Bupit
  • 10,406
  • 8
  • 39
  • 75
2

How about this bad boy:

^(\+|-)?([0-9]{1,11}?|)(?:\.[0-9]{1,4})?$

Seems to work =)

Dakota Brown
  • 730
  • 7
  • 20
2

My $.02

 ^(\+|-)?([0-9]{1,11}|)?(?:\.[0-9]{1,4})?$
Hogan
  • 69,564
  • 10
  • 76
  • 117
2

Keyword: The 0 is optional for POSITIVE numbers only.

You need separate statements for the positive and negative.

^(((\+?[0-9]{0,11})|(-[0-9]{1,11}))(?:\.[0-9]{1,4})*)$
Kenneth
  • 535
  • 2
  • 17
  • someone posted the following and then deleted it right away -- it seems to work perfectly... I'd like to give him credit, but his answer is gone.... ^(\+|-)?\.?[0-9]{1,11}?(?:\.[0-9]{1,4})?$ – Danimal111 Apr 28 '14 at 20:52
  • Your accepted answer does not force a 0 before the decimal point on negative numbers. This Regex now works correctly. – Kenneth Apr 28 '14 at 21:02
  • Thanks to @Hogan I see that answer is not quite right... it allows for 2 decimal points... I have accepted the answer from "John Bupit"... seems perfect... no time to test rest due to deadline.... but thanks for the help! – Danimal111 Apr 28 '14 at 21:03
  • Which expression allows two decimal points? Mine does not and is still the only expression here that does not allow a negative number without a leading 0. – Kenneth Apr 28 '14 at 21:13
2

All of your problems can be solved using a word boundary in the right place:

^(?:\+|-\b)?[0-9]{0,11}(?:\.[0-9]{1,4})?\b$
  • Changed {1,11} to {0,11} to allow zero digits before the decimal point.
  • \b after the minus sigh would not allow the decimal point immediately next to it.
  • \b at the end would not allow "+" or "-" as the whole string.

Working example (adapted from John): http://rubular.com/r/c7YLR25r3i

Community
  • 1
  • 1
Kobi
  • 135,331
  • 41
  • 252
  • 292