I need a regular expression that accomplishes the following:
Prohibits input values like:
012
0.00
0
0.0
0.000
Allows input values like:
1
0.01
1.12
10
10.5
Here’s the regular expression I am currently working with:
regex
^(?!0d)(?!0(.0{1,2})?$)d+(.d{1,2})?$
Could you please provide detailed information on what this regular expression does, and suggest any modifications if necessary to meet the requirements?
I would appreciate any help or clarification on how this expression works and how to adjust it for my needs.
Thank you!
user27358886 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
19
I would go with this regular expression:
^(?:[1-9]d*(?:.dd?)?|0.(?:[1-9]d?|0[1-9]))$
It combines various cases:
[1-9]d*(?:.dd?)?
This case is for numbers >= 1. They have to start with a non-zero digit ([1-9]
), can be followed by 0 or more digits (including 0,d*
), and optionally be followed by a literal dot with one or two digits ((?:.dd?)?
)0.(?:[1-9]d?|d[1-9])
This case covers numbers between 0 and 1: They start with a 0 followed by a decimal point (0.
), followed by two sub-cases enclosed in an non-capturing group(?: )
[1-9]d?
The number after the comma does not start with zero – but has only one or two digits.0[1-9]
The number after the comma does start with zero, but has to have a second digit that is not zero.
All that options are combined with the “or” operator |
and the whole expression is enclosed with “start of input” ^
and “end of input” $
to be sure that you do not only match a part of the whole input but e.g. a zero sneaks in before the expression that is just not matched.
A more technical and detailed explanation can be found at regex101, there you can also try several inputs and play around with the expression itself.
4
You may wish to attempt to match the following regular expression, which I have written in extended (aka free-spacing) mode (which disregards whitespace and comments) to make it self-documenting.
^ # match start of string
(?: # begin non-capture group
# match a positive integer
[1-9] # match a digit other than zero
d* # match zero or more digits
| # or
# match a positive float that does not end with a zero
(?: # begin non-capture group
0 # match a zero
| # or
# match an integer whose first digit is not zero
[1-9] # match a digit other than zero
d* # match zero or more digits
) # end non-capture group
. # match a period
d* # match zero or more digits
[1-9] # match a digit other than zero
) # end non-capture group
$ # match end of string
Note that this does not require look-around elements so it should work with most regex engines.
Demo
It may be helpful to first construct an outline of the needed expression.
^ # match start of string
# match a positive integer or a positive float
(?: # begin outer non-capture group
# match a positive integer
...
| # or
# match a positive float
(?: # begin inner non-capture group
0 # match a zero
| # or
# match an integer whose first digit is not zero
...
) # end inner non-capture group
. # match a period
# match zero or more digits
...
# match a digit other than zero
...
) # end outer non-capture group
$ # match end of string
If the comments and whitespaces are removed, and extended mode is not specified, the regular expression becomes
^(?:[1-9]d*|(?:0|[1-9]d*).d*[1-9])$
- If a number is a properly formatted float, it’s (an optional sequence of digits not starting with zero), then any digit (maybe zero), then point, then optional digits, then a non-zero digit.
- If a number is an integer, it’s a sequence of digits not starting with zero.
As there is probably no elegant way to partially merge those two variants, let’s simply combine them into:
^[1-9]d*$|^(?:[1-9]d*)?d.d*[1-9]$
Checking with your examples (in Python):
>>> rx = re.compile("^[1-9]d*$|^(?:[1-9]d*)?d.d*[1-9]$")
>>>
>>> rx.match("012")
>>> rx.match("0.00")
>>> rx.match("0")
>>> rx.match("0.0")
>>> rx.match("0.000")
>>>
>>> rx.match("1")
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> rx.match("0.01")
<_sre.SRE_Match object; span=(0, 4), match='0.01'>
>>> rx.match("1.12")
<_sre.SRE_Match object; span=(0, 4), match='1.12'>
>>> rx.match("10")
<_sre.SRE_Match object; span=(0, 2), match='10'>
>>> rx.match("10.5")
<_sre.SRE_Match object; span=(0, 4), match='10.5'>