RegEx match rational literals with decimals except incomplete rational literals - javascript

To match numbers like -3+-1.5/45,32, I'm trying to write a Regular Expression, and I'm very close to what I need.
I have the following (JavaScript) regular expression to match decimal numbers in a certain format:
( // 1st alternative:
( [+-]? // an optional unary +-
[\d_]* // 0-9 and _ digit separator any number of times
[,.]? // one of these decimal separators, once
[\d]+ // 0-9 at least once
)
| // 2nd alternative
( [+-]? // an optional unary +-
[\d_]+ // 0-9 and _ digit separator, at least once
[,.]? // one of these decimal separators, once
[\d]* // 0-9 any number of times
)
)
That is, the previous matches 10_00_0000.90, 1_00,99, 0.9, 9, and .9 but not . or ,.
Next, I experimented with this regex to match rational number expressions using the regex mentioned above.
([+-]?[\d_]*[+-]?(([+-]?[\d_]*[,.]?[\d]+)|([+-]?[\d_]+[,.]?[\d]*))\/(([+-]?[\d_]*[,.]?[\d]*)|([+-]?[\d_]+[,.]?[\d]*)))
It works like:
(
[+-]? // optional unary +-
[\d_]* // optional 0-9 and _ digit separator (for compound numbers)
[+-]? // optional infix +- for 2+3/2 OR 2-2/3
( // begin the regex from above, for before the / numer / denom separator
( // all as above
[+-]? // this is intentional: the numerator itself may be signed
[\d_]*
[,.]?
[\d]+
)
|
(
[+-]?
[\d_]+
[,.]?
[\d]*
)
)
\/ // numerator / denominator separator
(([+-]?[\d_]*[,.]?[\d]*)|([+-]?[\d_]+[,.]?[\d]*))) // same as above
You can find the regex and a couple of tests here (click "unit tests" on the left, then click the play button): https://regex101.com/r/bB8eO2/5
So you don't have to click, here are my tests:
/5 assert that regex does not match PASS
4/5 assert that capture group 1 equals 4/5 PASS
-1/3 assert that capture group 1 equals -1/3 PASS
3/-8 assert that capture group 1 equals 3/-8 PASS
+4.12/-.90 assert that capture group 1 equals +4.12/-.90 PASS
+1-6/7. assert that capture group 1 equals +1-6/7. PASS
1-+6/7 assert that capture group 1 equals 1-+6/7 PASS
-1+-.4/5. assert capture group 1 equals -1+-.4/5. PASS
-1+-.4/ assert regex does not match FAIL
Everything works properly except that one last failing test. I've fiddled with the quantifiers in the denominator, and I can get the last test to pass, but then trailing decimal separators [.,] are left out and the second-to-last and first test fail: https://regex101.com/r/mQ9mN8/1
This is for a lexer, so it would be nice to use a regex and not yet a proper parser to just test: is this thing a number, or is it an identifier?

You can use
([+-]?[\d_]*[+-]?(?:[+-]?(?:[\d_]+(?:[,.]\d*)?|[.,]\d+))\/(?:[+-]?(?:[\d_]+(?:‌​[,.]\d*)?|[.,]\d+)))
See this regex demo
Pattern breakdown:
(
[+-]?[\d_]*[+-]? # Optional + or - followed with 0+ digits or underscore and again optional - or +
(?:[+-]? # optional - or +
(?:[\d_]+ # 1+ digits or underscore
(?:[,.]\d*)? # Optional sequence of a . or , followed with 0+ digits
| # or
[.,]\d+ # , or , followed with 1+ digits
)
)
\/
(?:[+-]? # optional - or +
(?:[\d_]+ # 1+ digits or underscore
(?:‌​[,.]\d*)? # Optional sequence of a . or , followed with 0+ digits
| # or
[.,]\d+ # , or , followed with 1+ digits
)
)
)

Related

Regex pattern to not to include zeros

I need to match a pattern for validation . I want to match a decimal number where numeric part can have upto 14 digits including + or - without 0 and after decimal has upto 4 digits. Valid patterns are :
+1.23
9857.6543
-745290.0
Invalid patterns are:
0
0.00
1.23456
I have tried ^[0-9]{0,14}\.[0-9]{0,4}$.
I am not getting how to match for +,- and 0 condition
Short answer: ^[+-]?[1-9][0-9]{0,13}\.[0-9]{1,4}$
^ - start of string
[+-]? optionally, one between + and -
[1-9][0-9]{0,13} - a 14 digit number that doesn't start with 0
\. - decimal separator, has to be escaped or it will mean "any one character"
[0-9]{1,4} - up to 4 decimal digits
$ - end of string
This might work ^(\+|-)?(([1-9]|0(?=0*[1-9]))[0-9]{0,13}(\.[0-9]{1,4})?|0{1,14}\.(?=0*[1-9])[0-9]{1,4})$
^(\+|-)? - starts with +/-
(
([1-9]|0(?=0*[1-9]))[0-9]{0,13}(\.[0-9]{1,4})? - absolute value >= 1
| - or
0{1,14}\.(?=0*[1-9])[0-9]{1,4} - 0.**** with at least 1 non-zero digit
)
$ - end
const testcases = [
'+1.23',
'9857.6543',
'-745290.0',
'1.0',
'1.00',
'12',
'0.01',
'+001.01',
'0',
'0.00',
'1.23456',
'0.0',
'12.'];
const regex = /^(\+|-)?(([1-9]|0(?=0*[1-9]))[0-9]{0,13}(\.[0-9]{1,4})?|0{1,14}\.(?=0*[1-9])[0-9]{1,4})$/;
testcases.forEach(n => console.log(`${n}\t - ${regex.test(n)}`));
The pattern:
^[+-]?[^\D0]\d{0,13}\.\d{1,4}(?!\d)
matches the first 3 but not the second 3. [^\D0] is, if I'm not mistaken, strictly the same as [123456789], but slightly more compact.
You can assert that the string does not start with 1 or more zeroes, followed by an optional dot and optional zeroes.
Then match 1-14 digits and optionally a dot and 1-4 digits, which would also allow for 00001 for example
^(?!0+\.?0*$)[+-]?\d{1,14}(?:\.\d{1,4})?$
The pattern matches:
^ Start of string
(?!0+\.?0*$) Negative lookahead, assert not 1+ zeroes, optional dot and optional zeroes
[+-]? Optionally match + or -
\d{1,14} Match 1-14 digits
(?:\.\d{1,4})? Optionally match . and 1-4 digits
$ End of string
Regex demo
How about this?
^(?!0\.?0*$)[\+\-]?[0-9]{1,14}\.?[0-9]{0,4}$
Note: this does not match decimals without a leading 0 like .123 and does not match numbers with spaces in between the + or -. Though, these could be added to the pattern.
Requiring a non-zero digit before a . eliminates fractions of whole numbers, like 0.123.
Also, if you don't want integers and only want decimals, you will need to modify to make the . required:
^(?!0\.?0*$)[\+\-]?[0-9]{1,14}\.[0-9]{0,4}$

regex for simple arithmetic expression

I've read other stackoverflow posts about a simple arithmetic expression regex, but none of them is working with my issue:
I need to validate this kind of expression: "12+5.6-3.51-1.06",
I tried
const mathre = /(\d+(.)?\d*)([+-])?(\d+(.)?\d*)*/;
console.log("12+5.6-3.51-1.06".match(mathre));
but the result is '12+5', and I can't figure why ?
You only get 12.5 as a match, as there is not /g global flag, but if you would enable the global flag it will give partial matches as there are no anchors ^ and $ in the pattern validating the whole string.
The [+-] is only matched once, which should be repeated to match it multiple times.
Currently the pattern will match 1+2+3 but it will also match 1a1+2b2 as the dot is not escaped and can match any character (use \. to match it literally).
For starting with digits and optional decimal parts and repeating 1 or more times a + or -:
^\d+(?:\.\d+)?(?:[-+]\d+(?:\.\d+)?)+$
Regex demo
If the values can start with optional plus and minus and can also be decimals without leading digits:
^[+-]?\d*\.?\d+(?:[-+][+-]?\d*\.?\d+)+$
^ Start of string
[+-]? Optional + or -
\d*\.\d+ Match *+ digits with optional . and 1+ digits
(?: Non capture group
[-+] Match a + or -
[+-]?\d*\.\d+ Match an optional + or - 0+ digits and optional . and 1+ digits
)+ Close the noncapture group and repeat 1+ times to match at least a single + or -
$ End of string
Regex demo
You would try to use this solution for PCRE compatible RegExp engine:
^(?:(-?\d+(?:[\.,]{1}\d)?)[+-]?)*(?1)$
^ Start of String
(?: Non capture group ng1
(-?\d+(?:[\.,]{1}\d)?) Pattern for digit with or without start
"-" and with "." or "," in the middle, matches 1 or 1.1 or 1,1
(Matching group 1)
[+-]? Pattern for "+" or "-"
)* Says
that group ng1 might to repeat 0 or more times
(?1) Says that
it must be a digit in the end of pattern by reference to the first subpattern
$ End of string
As JS does not support recursive reference, you may use full version instead:
/^(?:(-?\d+(?:[\.,]{1}\d)?)[+-]?)*(-?\d+(?:[\.,]{1}\d)?)$/gm

regex to only allow an input to 3 decimal places with 0.001 being the smallest number possible, not 0

I am trying to write a regex to allow a user enter a positive number and to 3 decimal places. My regex looks like this, however, it isn't working as I would like.
/\d*[1-9](\.\d{0,3})?/
This allows the user to enter 1.000 as the smallest number, however, it doesn't allow a user to enter 0.001 which should be the smallest number possible to enter into the input.
Does anyone know what the regex should be to solve this?
Your code has another issue where it can not match 10 since you are not allowing the ones place to be 0.
You need to use some or statements
const re = /(^([1-9]|\d{2,})(\.\d{0,3})?|0\.\d{0,2}[1-9])$/
const tests = ["0.001", "0.1", "0","0.0", "0.000","10.001", "10","11","1"]
tests.forEach(n => console.log(n, re.test(n)))
const re = /^(?!0+(?:\.0+)?$)\d+(?:\.\d+)?$/
const tests = ["0.001", "0.1", "0","0.0", "0.000","10.001", "10","11","1","1.22","1.222"]
tests.forEach(n => console.log(n, re.test(n)))
Explanation:
^ # beginning of string
(?! # negative lookahead, make sure we haven't after:
0+ # 1 or more zero
(?: # start non capture group
\. # a dot
0+ # 1 or more zero
)? # end group, optional
$ # end of string
) # end lookahead
\d+ # 1 or more digits
(?: # start non capture group
\. # a dot
\d+ # 1 or more digits
)? # end group, optionnal
$ # end of string
Personally I would just check for 0 and make the regex a lot simpler, but here is a solution, where the required decimal places can be adjusted by changing {1,3}.
The jist of this regex is that we allow any number greater than two digits , then allow only 1-9 for one digit, then optionally require up to 1 decimal with 1-3 digits afterwards.
const r = /^((([0-9]{2,}){1}|[1-9]{1})(\.[0-9]{1,3}){0,1})$/;
const tests = ['1','2','0','1.001','1.001.1','999.001','9.01','9.0100','abc'];
tests.forEach(t=>console.log(t,r.test(t)));
Another option is to use a negative lookahead to assert from the start of the string what is on the right is neither a dot or zero repeated until the end of the string:
^(?![0.]+$)\d+(?:\.\d{1,3})?$
See a Regex demo
Explanation
^ Start of the string
(?![0.]+$) Negative lookahead to assert what is on the right is not what is listed in the character class repeated 1+ times until the end of the string
\d+ Match 1+ times a digit
(?:\.\d{1,3})? Optional non capturing group which matches a dot and 1+ times a digit
$ End of the string
const tests = ["0.001", "0.1", "0","0.0", "0.000","10.001", "10","11","1","1.22","1.222"]
tests.forEach(n => console.log(parseFloat(n) >= 0.001))
I really think this is being overthought.
The answer is here.
([1-9]\.[0-9][0-9][0-9]|[0]\.[1-9][0-9][0-9]|[0]\.[0][1-9][0-9]|[0]\.[0][0][1-9])
This should match 0.001~9.999

Regex to match any set of numbers except the 10 digit numbers starting with 7

I want to capture all numbers(any no.of digits) except the 10 digit numbers starting with 7.
71234567890 - should match
7123456789 - should not match
1234567890- should match
Use the pattern
/7\d{9}|(\d+)/
^^^^^^ MATCH 10-DIGIT NUMBER STARTING WITH SEVEN, DO NOT CAPTURE
^ --OR--
^^^^^ MATCH OTHER SEQUENCES OF DIGITS AND DO CAPTURE
This will match the 10-digit number starting with 7 but not capture it; otherwise, it will match the sequence of digits and capture it.
Now
'7123456789'.match(regexp)
["7123456789", undefined]
'1234567890'.match(regexp)
["1234567890", "1234567890"]
In other words, the captured string will be found in the second element of the array returned by match.
If you want to anchor this to the beginning and end of the string, then
/^7\d{9}$|(^\d+$)/
You could also do this with a negative look-ahead, as suggested in the comments, but it's not needed here and could be a bit of a stretch for beginning regexpers.
(?:(?:^|\D)(7\d{1,8}|7\d{10,})(?:\D|$))
See the DEMO
In order to get any number of digits except a string of 10 digits starting with '7'
you'd have to special case the '7'. There is really no way around it.
The fastest way is a pure regex solution, since the engine stays inside
running c++ engine code and does not interact with the host language.
There are two ways, either anchored or mid-string.
Anchored: ^(?:7(?!\d{9}$)|[012345689])\d*$
(number string is the overall match, i.e. in capture group 0)
^ # Beginning of string
(?: # Cluster, get first digit
7 # '7'
(?! \d{9} $) # not followed by nine more digits
| # or
[012345689] # Any digit except '7' (i.e. [^\D7])
) # End cluster
\d* # Get optional remaining digits
$
Mid-string: (?:^|\D)((?:7(?!\d{9}(?:\D|$))|[012345689])\d*)
(number string is in capture group 1)
(?: ^ | \D ) # Beginning of string or not a digit
( # (1 start), The number
(?: # Cluster, get first digit
7 # '7'
(?! # Assertion, not followed by nine more digits
\d{9}
(?: \D | $ ) # (forces no more/less than nine) digits
)
| # or
[012345689] # Any digit except '7' (i.e. [^\D7])
) # End cluster
\d* # Get optional remaining digits
) # (1 end)

Regular expression for the specific format (Valid Decimal digits enclosed in left and right parenthesis)

We need a regular expression which should accept a valid decimal digits upto 2 decimal points with option of it being enclosed in left and right parenthesis
Valid Examples :
45.78
99.34
12202.45
(45.22)
(65.00)
(1255.00)
Could any one help us out on this.
Solution
^(\d+(?:\.\d{1,2})?)$|^(\(\d+(?:\.\d{1,2})?\))$
Regex Test
What matches
50
50.00
(50)
(50.00)
Explanation
^ //Start of string
( // Start capturing group
\d+ // Digit 1 or more times
(?: // Start Non capturing group
\. // Dot
\d{1,2} // Digit 1 to 2 times
)? // End non capturing group and ? means conditional
) // End capturing group
$ //End of string
| //OR (Now we check for numbers enclosed in parenthesis)
^ //Start of string
( // Start capturing group
\( // Match Left Parenthesis
\d+(?:\.\d{1,2})? // Same as above
\) // Match Right Parenthesis
) // End capturing group
$ //End of string

Categories