Match decimal numbers

Viewed 109

I would like to match decimal numbers like:

0.0
0.12
1.00
1.12
-0.123
-1.000
-1.123

without matching negative zeros: -0.0 or -0.00, -0.000 etc.

I have no idea how to extend the /^-?[0-9]+\.[0-9]+$/ regex to not to allow negative zeros.

UPDATE:

  • No leading zeros allowed: 01.1 or -01.1
  • Whole and fractional characters are required (.5 or 5. not allowed)
3 Answers

IIUC, you just need to add a negative lookahead (?!-0\.0+$):

^(?!-0\.0+$)-?\d+\.\d+$

Example:

echo '0.0
0.12
1.00
1.12
-0.123
-1.000
-1.123
-0.00
-0.0
-0.000010
-12.34
' | perl -lne 'print if /^(?!-0\.0+$)-?\d+\.\d+$/'
#0.0
#0.12
#1.00
#1.12
#-0.123
#-1.000
#-1.123
#-0.000010
#-12.34

You can use

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

https://regex101.com/r/z51Jpu/5

The idea is, after matching the -, match either a non-zero in the integer part, or match a zero eventually followed by a non-zero.

  • ^-? - Beginning of the string, optional -
  • (?:[1-9]\.[0-9]*|0\.0*[1-9][0-9]*) - Match either:
    • 0*[1-9][0-9]*\.[0-9]* A non-zero integer part, followed by a decimal part or
    • 0\.0*[1-9][0-9]* - A zero integer part, with a decimal part that has a non-zero somewhere
  • $ - End of string

Could also lookahead for a digit between 1 and 9 somewhere in the line, then use your original pattern:

^-?(?=[0.]*[1-9])[0-9]+\.[0-9]+$
   ^^^^^^^^^^^^^^

https://regex101.com/r/z51Jpu/6

Here's a crude but effective approach: enumerate all of the possibilities and use alternation.

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

Note that your rules permit matching leading zeroes on a number, for example, 01.1 or -01.0. You can reject these with the even more crude

^(-?0\.\d*[1-9]\d*|-[1-9]\d*\.\d*[1-9]\d*|-[1-9]\d*\.\d+|^[1-9]\d*\.\d+|0.0+)$

Tests:

const permissive = /^(-\d+\.\d*[1-9]\d*|-\d*[1-9]\d*\.\d+|^\d+\.\d+)$/;
const strict = /^(-?0\.\d*[1-9]\d*|-[1-9]\d*\.\d*[1-9]\d*|-[1-9]\d*\.\d+|^[1-9]\d*\.\d+|0.0+)$/;

`
0.0
0.00
0.001
0.12
1.00
1.12
-0.123
-1.000
-1.123
10.10
2.2
-2.2
0.00
-10.010
0.101

-0.0
-0.00
-0.000
-2.
.0
-.0
.012
1.
12.
00.
0.

-001.0
-01.0
01.1
010.1010
000.000
00.0
`.split("\n").filter(e => e).forEach(test => 
  console.log(
    test, "=> permissive:", permissive.test(test), 
    "... strict:", strict.test(test)
  )
);

Related