Decimal number regular expression, where digit after decimal is optional
Asked Answered
W

18

181

I need a regular expression that validates a number, but doesn't require a digit after the decimal. ie.

123
123.
123.4

would all be valid

123..

would be invalid

Any would be greatly appreciated!

Weisbart answered 24/8, 2012 at 21:40 Comment(1)
P
286

Use the following:

/^\d*\.?\d*$/
  • ^ - Beginning of the line;
  • \d* - 0 or more digits;
  • \.? - An optional dot (escaped, because in regex, . is a special character);
  • \d* - 0 or more digits (the decimal part);
  • $ - End of the line.

This allows for .5 decimal rather than requiring the leading zero, such as 0.5

Pecuniary answered 24/8, 2012 at 21:43 Comment(10)
@OrangeDog, your original matches more than might be desired. e.g. 'cow3.45tornado' ;)Scabby
@S. Albano, OrangeDog's original regex,\d+\.?\d*, would have matched '3.45' in 'cow3.45tornado'!Shipway
Yes, my point was that it might not be a desired behavior given the set of examples Trish gave. OrangeDog then added the second regex, which improved his answer and match that of João, who was getting the upvotes.Scabby
It also matches a single dot which is not a valid decimal number. A better regex would be /^\d*\.?\d+$/ which would force a digit after a decimal point.Voronezh
@Voronezh and it matches an empty string, which your change would also solve.Knotts
@Voronezh "doesn't require a digit after the decimal"Raynell
Incorrect. It matches a lone dot, too. And it is NOT the decimal numberNubile
This solution doesn't work. It requires decimals while OP clearly says: optional decimals.Diabetes
This will also match 000.2 or the empty string, which are probably not what's desired.Apia
Why is single dot not a number actually?Christoforo
R
155
/\d+\.?\d*/

One or more digits (\d+), optional period (\.?), zero or more digits (\d*).

Depending on your usage or regex engine you may need to add start/end line anchors:

/^\d+\.?\d*$/

Regular expression visualization

Debuggex Demo

Raynell answered 24/8, 2012 at 21:43 Comment(15)
Yeah, but the top voted answer is wrong, it matches both . and the empty string.Raynell
But your answer does NOT take ".1", that is a correct decimal number!Nubile
@Nubile the question has an odd definition of "decimal number". My answer is the correct answer to the question.Raynell
The question forbids "2..", but not ".2". It is strange only in allowing "2.", that is a bit untraditional.Nubile
@Nubile Nor does it say that ".digit" should be matched. If they wanted that, then they should have said.Raynell
This is an evil regex (aka ReDoS).Cotinga
@EqualityInTech I'm pretty sure it's not - it has no grouping at all.Raynell
Hmm... I think I might not fully understand evil regexes like I thought I did. Sorry.Cotinga
Decimals often include negative numbers. Does this match correctly for -1 and not - .Silvanasilvano
@AlexanderRyanBaggett this matches exactly what the question specified. As you can see it doesn't include - at all.Raynell
What would the regex be if we anted to also accept empty strings? I have an issue where I can't get rid of the last character while backspacing.Acropetal
@RaulMarquez simplest way is to add | at the end.Raynell
this doesnt allow a . after a number, so how do you type 1.Houseclean
@Houseclean yes it does, and it explains how. Why don't you try it?Raynell
@Raynell it didn’t work in my environment, but it’s possible something else was effecting itHouseclean
W
102

You need a regular expression like the following to do it properly:

/^[+-]?((\d+(\.\d*)?)|(\.\d+))$/

The same expression with whitespace, using the extended modifier (as supported by Perl):

/^  [+-]? ( (\d+ (\.\d*)?)  |  (\.\d+) ) $/x

or with comments:

/^           # Beginning of string
 [+-]?       # Optional plus or minus character
 (           # Followed by either:
   (           #   Start of first option
     \d+       #   One or more digits
     (\.\d*)?  #   Optionally followed by: one decimal point and zero or more digits
   )           #   End of first option
   |           # or
   (\.\d+)     #   One decimal point followed by one or more digits
 )           # End of grouping of the OR options
 $           # End of string (i.e. no extra characters remaining)
 /x          # Extended modifier (allows whitespace & comments in regular expression)

For example, it will match:

  • 123
  • 23.45
  • 34.
  • .45
  • -123
  • -273.15
  • -42.
  • -.45
  • +516
  • +9.8
  • +2.
  • +.5

And will reject these non-numbers:

  • . (single decimal point)
  • -. (negative decimal point)
  • +. (plus decimal point)
  • (empty string)

The simpler solutions can incorrectly reject valid numbers or match these non-numbers.

Wolof answered 26/5, 2014 at 14:10 Comment(8)
Best because it matches a number followed by a period (42.). However there is a bug/false positive as it matches this: 3....3 which can be fixed by adding two more parenthesis to enforce ^$ beginning and end characters: /^([+-]?(\d+(\.\d*)?)|(\.\d+))$/Oringas
Thanks Pete, well spotted. The answer has now been corrected, by adding extra parenthesis so it behaves as intended. It is now written like ^A?(B|C)$. Previously, it was written like ^A?B|C$ which actually means (^A?B)|(C$) which was incorrect. Note: ^(A?B|C)$ is also incorrect, because it actually means ^((A?B)|(C))$ which would not match "+.5".Wolof
This is the best answer. The other answers don't handle all cases. I do a similar thing myself except that I use a lookahead to handle the missing-digit cases: /^[+-]?(?=\d|\.\d)\d*(\.\d*)?$/Painty
That is the only correct regex here. But some people would disagreee with "34.". I would propose + after second d instead of *Nubile
@Nubile "123." is specifically listed as valid in the question.Raynell
@Raynell Yes. But here will come other people, too. I think, it would be better to add that variant for "traditional" users. But I am afraid, I had found bad lines: "-0", "-0.", "-0.0", "-.0", and another family: "000", "0001". The second family is easy to manage, but the first one will take many additional symbols.Nubile
This also matches 0000.2, which is probably not what's desired.Apia
There is an answer by James Miao below that rejects 0000.2 and 01 for exampleNosey
E
29

this matches all requirements:

^\d+(\.\d+)?$
Exasperation answered 5/9, 2013 at 11:11 Comment(1)
For me this is the best answer, since the string: "4." (for example) is not a valid number at least in ruby language. However, the most upvoted answers accepts "4." as a number regex, which is wrong.Hernardo
M
21

Try this regex:

\d+\.?\d*

\d+ digits before optional decimal
.? optional decimal(optional due to the ? quantifier)
\d* optional digits after decimal

Monmouthshire answered 24/8, 2012 at 21:43 Comment(6)
Nope, that one does not match 123.Lucianolucias
Thanks for the note. Modified my regex.Monmouthshire
Indeed, but now you just edited it into what is already posted by someone else. Consider just removing yet another "correct" answer.Lucianolucias
@BartKiers I upvoted this because the answer you're referring to has an additional slash at the beginning so it didn't work for me. This worked.Rachaba
@Rachaba that slash is a regex delimiter: not part of the pattern itself. You will see many answers containing these delimiters.Lucianolucias
Ah ok. Thanks. Anyway, for someone like me who doesn't know, the answer is good because otherwise I wouldn't know.Rachaba
M
8

I ended up using the following:

^\d*\.?\d+$

This makes the following invalid:

.
3.
Mckellar answered 11/2, 2015 at 22:24 Comment(1)
You might need slashes depending on which language you're using. For example: /^\d*\.?\d+$/Mckellar
O
7

This is what I did. It's more strict than any of the above (and more correct than some):

^0$|^[1-9]\d*$|^\.\d+$|^0\.\d*$|^[1-9]\d*\.\d*$

Strings that passes:

0
0.
1
123
123.
123.4
.0
.0123
.123
0.123
1.234
12.34

Strings that fails:

.
00000
01
.0.
..
00.123
02.134
Orbit answered 7/2, 2016 at 21:27 Comment(0)
A
6

you can use this:

^\d+(\.\d)?\d*$

matches:
11
11.1
0.2

does not match:
.2
2.
2.6.9

Against answered 6/11, 2018 at 9:45 Comment(1)
Thanks, very simple and matches what I needIgnace
A
5
^[+-]?(([1-9][0-9]*)?[0-9](\.[0-9]*)?|\.[0-9]+)$

should reflect what people usually think of as a well formed decimal number.

The digits before the decimal point can be either a single digit, in which case it can be from 0 to 9, or more than one digits, in which case it cannot start with a 0.

If there are any digits present before the decimal sign, then the decimal and the digits following it are optional. Otherwise, a decimal has to be present followed by at least one digit. Note that multiple trailing 0's are allowed after the decimal point.

grep -E '^[+-]?(([1-9][0-9]*)?[0-9](\.[0-9]*)?|\.[0-9]+)$'

correctly matches the following:

9
0
10
10.
0.
0.0
0.100
0.10
0.01
10.0
10.10
.0
.1
.00
.100
.001

as well as their signed equivalents, whereas it rejects the following:

.
00
01
00.0
01.3

and their signed equivalents, as well as the empty string.

Apia answered 8/10, 2019 at 6:33 Comment(0)
P
3

try this. ^[0-9]\d{0,9}(\.\d{1,3})?%?$ it is tested and worked for me.

Precancel answered 4/2, 2020 at 19:32 Comment(0)
E
2

What language? In Perl style: ^\d+(\.\d*)?$

Elora answered 24/8, 2012 at 21:50 Comment(0)
C
2

What you asked is already answered so this is just an additional info for those who want only 2 decimal digits if optional decimal point is entered:

^\d+(\.\d{2})?$

^ : start of the string
\d : a digit (equal to [0-9])
+ : one and unlimited times

Capturing Group (.\d{2})?
? : zero and one times . : character .
\d : a digit (equal to [0-9])
{2} : exactly 2 times
$ : end of the string

1 : match
123 : match
123.00 : match
123. : no match
123.. : no match
123.0 : no match
123.000 : no match
123.00.00 : no match

Changeover answered 26/6, 2019 at 15:44 Comment(2)
Does this match negative numbers?Silvanasilvano
@AlexanderRyanBaggett you need to check for the negative sign so it would be: ^-?\d+(\.\d{2})?$Changeover
M
2

Regular expression:

^\d+((.)|(.\d{0,1})?)$

use \d+ instead of \d{0,1} if you want to allow more then one number use \d{0,2} instead of \d{0,1} if you want to allow up to two numbers after coma. See the example below for reference:

enter image description here

or

^\d+((.)|(.\d{0,2})?)$

enter image description here

or

^\d+((.)|(.\d+)?)$

enter image description here

Explanation

(These are generated by regex101)

  • ^ asserts position at start of a line
  • \d matches a digit (equivalent to [0-9])
  • + matches the previous token between one and unlimited times, as many times as possible, giving back as needed (greedy)
  • 1st Capturing Group ((.)|(.\d{0,1})?)
  • 1st Alternative (.)
  • 2nd Capturing Group (.)
  • . matches any character (except for line terminators)
  • 2nd Alternative (.\d{0,1})?
  • 3rd Capturing Group (.\d{0,1})?
  • ? matches the previous token between zero and one times, as many times as possible, giving back as needed (greedy)
  • . matches any character (except for line terminators)
  • \d matches a digit (equivalent to [0-9])
  • {0,1} matches the previous token between zero and one times, as many times as possible, giving back as needed (greedy)
  • $ asserts position at the end of a line

Sandbox

Play with regex here: https://regex101.com/

Mccaffrey answered 9/9, 2021 at 3:17 Comment(2)
Thanks for the well explained answer. I wanted 3 decimal places for road chainages implementation and it helped.Exocrine
Dots should be escaped. Otherwise, it will accept any character as the separator e.g. 123a1.Cahn
I
2

For those who wanna match the same thing as JavaScript does:

[-+]?(\d+\.?\d*|\.\d+)

Matches:

  • 1
  • +1
  • -1
  • 0.1
  • -1.
  • .1
  • +.1

Railroad diagram of the regex

Drawing: https://regexper.com/#%5B-%2B%5D%3F%28%5Cd%2B%5C.%3F%5Cd*%7C%5C.%5Cd%2B%29

Indivertible answered 28/10, 2022 at 22:9 Comment(0)
R
1
(?<![^d])\d+(?:\.\d+)?(?![^d])

clean and simple.

This uses Suffix and Prefix, RegEx features.

It directly returns true - false for IsMatch condition

Radiosurgery answered 21/3, 2014 at 10:50 Comment(0)
O
1
^\d+(()|(\.\d+)?)$

Came up with this. Allows both integer and decimal, but forces a complete decimal (leading and trailing numbers) if you decide to enter a decimal.

Oolite answered 12/2, 2015 at 10:12 Comment(0)
R
0

In Perl, use Regexp::Common which will allow you to assemble a finely-tuned regular expression for your particular number format. If you are not using Perl, the generated regular expression can still typically be used by other languages.

Printing the result of generating the example regular expressions in Regexp::Common::Number:

$ perl -MRegexp::Common=number -E 'say $RE{num}{int}'
(?:(?:[-+]?)(?:[0123456789]+))

$ perl -MRegexp::Common=number -E 'say $RE{num}{real}'
(?:(?i)(?:[-+]?)(?:(?=[.]?[0123456789])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[-+]?)(?:[0123456789]+))|))

$ perl -MRegexp::Common=number -E 'say $RE{num}{real}{-base=>16}'
(?:(?i)(?:[-+]?)(?:(?=[.]?[0123456789ABCDEF])(?:[0123456789ABCDEF]*)(?:(?:[.])(?:[0123456789ABCDEF]{0,}))?)(?:(?:[G])(?:(?:[-+]?)(?:[0123456789ABCDEF]+))|))
Robalo answered 5/9, 2013 at 12:8 Comment(0)
A
0

All of the regexes here are wrong because they don't consider a lot of edge cases:

  • US format of numbers (1,000,000.00) vs. non-US (1.000.000,00)

Assuming only the US format the following numbers are valid:

0.1
.1

1
12
123

1234
1,234

12345
12,345

123456
123,456

123456789
123,456,789

1.0
12.0
123.0

1234.0
1,234.0

12345.0
12,345.0

123456.0
123,456.0

123456789.0
123,456,789.0

+0.1
+.1

+1.0
+12.0
+123.0

+1234.0
+1,234.0

+12345.0
+12,345.0

+123456.0
+123,456.0

+123456789.0
+123,456,789.0

-0.1
-.1

-1.0
-12.0
-123.0

-1234.0
-1,234.0

-12345.0
-12,345.0

-123456.0
-123,456.0

-123456789.0
-123,456,789.0

Assuming only the US format the following numbers are invalid:

1,000,
1,4
1,00
1,000,1
1,000,10

1.1.
1..1
..1
.1.
-1.1.
-1..1
-..1
-.1.

The following regex matches only the valid US numbers:

^[+-]?((\d*)|(\d{1,3}(,\d{3})+))(\.\d+)?$

if you want non-US numbers:

^[+-]?((\d*)|(\d{1,3}(\.\d{3})+))(,\d+)?$

see https://regexr.com/7guqk

Edit 1:

BTW: In some cases, numbers are represented in exponential form

4800 -> 4.80000000000000E+03

My regex doesn't consider those numbers yet.

Alexandrine answered 13/7, 2023 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.