Regular Expression to match amounts - c++

I have this regular expression:
^-?([0-9]{1,3})+([ 0-9]{3})*([\.0-9]{2})?$
Format should be marked as valid:
190 254 254
10 254 254
1 254 982
250 254
10 254
1 154
190 254 254.22
10 254 254.22
1 254 982.22
250 254.22
10 254.22
1 154.22
-190 254 254
-10 254 254
-1 254 982
-250 254
-10 254
-1 154
-190 254 254.22
-10 254 254.22
-1 254 982.22
-250 254.22
-10 254.22
-1 154.22
But after I tested it here I got only partial matching.
UPDATE:
After correcting the regular expression by Mr #anubhava, the QLineEdit now accepts other formats too:
4654d654
55d54
444444
These is how I validate the input:
QRegExp rx("^-?[0-9]{1,3}(?: [0-9]{3})*(?:\.[0-9]{0,2})?$");
QValidator *currencyValidator = new QRegExpValidator(rx, this);
ui->unitPrice->setValidator(currencyValidator);
It turns out that I didn't escape the backslash:
QRegExp rx("^-?[0-9]{1,3}(?: [0-9]{3})*(?:\\.[0-9]{0,2})?$");
^

You can fix it by modifying your regex to this:
^-?[0-9]{1,3}(?: [0-9]{3})*(?:\.[0-9]{0,2})?$
Rather than keeping space and DOT inside the character class match them before the character classes.
Updated Regex Demo

This segment ([0-9]{1,3})+ means:
( Start of capturing group
[0-9] Match digit
{1,3} Match 1-3 of previous (digit)
) End of capturing group
+ Match 1 or more of previous (capturing group)
The result is that it will match 1 or more digits, capturing the last 1-3 digits.
Since {1,3} is greedy, it prefers matching 3, so for input 12345678, that means:
123 First repetition of capturing group
456 Second repetition of capturing group
78 Third repetition of capturing group
And since only the last repetition of the group is actually captured, you get 78, which is not what you want. See this regex101 for more info.
That was just the first of three segments of your regex. All three segments are mixing {n,m} with + or *. + is just shorthand for {1,}, * is shorthand for {0,}, and ? is shorthand for {0,1}.
So, x{1,3}+ really means x{1,3}{1,}, and that makes no sense, so stop doubling the repetitions.
So, what should your regex be? Probably something like this:
(-?[0-9]{1,3})(?: ([0-9]{3}))? ([0-9]{3}(?:\.[0-9]{2})?)
For input -190 254 254.22, that will return -190, 254, and 254.22. See this regex101 for full test.

Related

Regular expression for non negative integers including 0

How can I represent non negative integers including 0 and no integer, except 0 should start by a 0 using regular expression?
Example:
111 (true)|
0 (true)|
013 (false)|
120 (true)|
The regex I tried:
^(0|[1-9][0-9]?)$
This is how it's represented if 0 isn't included.
Try (regex101):
^(?!0\d+)\d+
Which evaluates:
111 - True
0 - True
013 - False
120 - True
You can change the quantifier from ? (which matches 0 or 1 times) to * which matches zero or more times.
Now the pattern matches either a single 0 or a digit that starts with 1-9 followed by optional digits 0-9.
^(?:0|[1-9][0-9]*)$
Regex demo
Or if a non capture group is not supported
^(0|[1-9][0-9]*)$

Regex Conditional validation

I have a input field, and I want to create a regex that only receive input value from 0.00 to 100.00(include both). I have created a regex check:
^1?\d{0,2}(\.\d{1,2})?$
But with this one, it not only accept values from 0.00 to 100.00 but also accept the input from 100.01 to 199.99.
How can I set a condition that if there are three digital before the dot, it can be only 100 and the decimals part is 00 or 0 only if having decimals?
So 100.00, 100.0 or 100 are the only accept for the values over 99.99 and the input between 100.01 to 199.99 is not pass.
Here are some passed input:
100
100.00
100.0
3
0
0.00
5.2
8.21
37.23
Here are some not passed:
40.323
100.50
101.50
199.99
40.
100.
This should work:
^((?:100(?:\.00?)?)|(?:\d\d?(?:\.\d\d?)?))$
It matches:
x
x.x
x.xx
xx
xx.x
xx.xx
100
100.0
100.00
You can get the match via directly match or with the first capturing group :)
P.S. BTW, #Ouroborus's solution (in comments) also works, and his solution unexpectedly having the exact same length as mine lol:
^(?=.)(100(\.0{1,2})?|\d{1,2}(\.\d{1,2})?)$
You can match 0 - 99 with 1 or 2 optional decimals or 100 with optional .0 or .00
^(?:\d\d?(?:\.\d\d?)?|100(?:\.00?)?)$
The pattern in parts:
^ Start of string
(?: Non capture group
\d\d? Match 1-2 digits
(?:\.\d\d?)? Optionally match . and 1-2 digits
| or
100(?:\.00?)? Match 100 or 100.0 or 100.00
) Close non capture group
$ End of string
Regex demo
Try this:
^(100(\.00?)?|\d\d?)(\.\d\d?)?$
See live demo.
Regex:
^ = start
(100|\d\d?) = literal 100 or 1 or 2 digits
(\.\d\d?)? = dot then 1 or 2 digits, all optional
$ = end

Google form RegEx validation that matches all numbers and ranges

In my Google form I would like to authorize numbers and range of numbers like this:
1 to 9,
10 to 80,
90,
100
The separator can be , | ; or newline character, other examples
100
110 to 115
540
or
50 | 60 | 70 to 80 | 100
I was expecting this regEx to work (selecting Regular Expression > Matches > (to)|[0-9 \n|,;]*) but it failed.
Any idea ?
You can use
^\d+(?:(?:\s*(?:to|[\n|;,])\s*)\d+)*\n*$
See the regex demo. Details:
^ - start of a string
\d+ - one or more digits
(?:\s*(?:to|[|;,])\s*\d+)* - zero or more occurrences of
\s*(?:to|[\n|;,])\s* - to or |, ;, , or newline enclosed with zero or more whitespaces
\d+ - one or more digits
\n* - zero or more newlines
$ - end of string.

Elegant way to find repeated digits in Raku (née Perl 6)

I'm trying to find groups of repeated digits in a number, e.g. 12334555611 becomes (1 2 33 4 555 6 11).
This works:
$n.comb(/ 0+ | 1+ | 2+ | 3+ | 4+ | 5+ | 6+ | 7+ | 8+ | 9+ /)
but is not very elegant.
Is there a better way to do this?
'12334555611'.comb(/\d+ % <same>/)
Please check the answer of the first task of Perl Weekly Challenge
You may use
$n.comb(/(.) $0*/)
The (.) creates a capturing group and captures any char into Group 1, then there is a backreference to Group 1 that is $0 in Perl6 regex. The * quantifier matches zero or more occurrences of the same char as in Group 1.
Replace the . with \d to match any digit if you need to only match repeated digits.
See a Perl6 demo online.
In case someone navigates here wanting to remove singleton digits (Raku REPL code below):
Returning only the longest run(s) of repeated digits, while removing singleton digits (uses m:g adverb combo):
> put $/ if m:g/ \d**2..* % <same> / given '12334555611';
33 555 11
Alternatively, depending on how you interpret the original question, returning the overlapping runs of repeated digits (uses m:ov adverb combo):
> put $/ if m:ov/ \d**2..* % <same> / given '12334555611';
33 555 55 11
The difference between the two versions is particularly dramatic as repeated runs get longer:
> given '122333444455555666666' {put $/ if m:g/ \d**2..* % <same> /};
22 333 4444 55555 666666
> given '122333444455555666666' {put $/ if m:ov/ \d**2..* % <same> /};
22 333 33 4444 444 44 55555 5555 555 55 666666 66666 6666 666 66

PCI Compliance regex detect pattern with spaces

I have to generate a regular expression to detect patterns of text where credit card numbers are involved, I have a regular expression but fails when the text is altered with simple spaces between the text for example (not valid credit card number):
4320 7589 9456 0123
The regex is:
4\d{3}(\s+|-)?\d{4}(\s+|-)?\d{4}(\s+|-)?\d{4}
This regex match easy, but if someone alter the text with spaces between any number like this:
4 320 7589 9456 0123
Does not match, I need a regex to detect any possible variable with spaces, special symbols, letters, some examples:
43 20 75 89 94 56 01 23
4 3 2 0 7 5 8 9 9 4 5 6 0 1 2 3
4320a7589b9456c0123
4320$7589$9456$0123
4320_7589_9456_0123
I don't know if I can strip any space, symbols from the pattern to analyze the text?
I am posting because you actually asked for help with pattern to match any number of non-digits between the first 4 and 15 more digits.
The pattern is
^4(?:\D*\d){15}$
See demo
Regex breakdown:
^ - start of string
4 - literal 4
(?:\D*\d){15} - 15 occurrences of sequences of...
\D* - 0 or more non-digit symbols before..
\d - a digit
$ - end of string
If you need to capture, you can capture (like ^4((?:\D*\d){3})((?:\D*\d){4})((?:\D*\d){4})((?:\D*\d){4})$), but the submatches will still contain the "junk" in-between digits.