I am trying to validate a comma separated list of numbers 1-31 unique (not repeating).
i.e.
2,4,6,7,1 is valid input.
2,2,6 is invalid
2 is valid
2, is invalid
1,2,3,4,15,6,7,31 is valid
1,2,3,4,15,6,7,32 is invalid
20,15,3
I tried
^((([0]?[1-9])|([1-2][0-9])|(3[01]))(?!([0]?[1-9])|([1-2][0-9])|(3[01])*,\\1(?!([0]?[1-9])|([1-2][0-9])|(3[01])) but it's accepting repeating numbers
For a number range that exceeds 1 digit, just add word boundary's around
the capture group and the back reference.
This isolates a complete number.
This particular one is numb range 1-31
^ # BOS
(?! # Validate no dups
.*
( # (1 start)
\b
(?: [1-9] | [1-2] \d | 3 [0-1] ) # number range 1-31
\b
) # (1 end)
.*
\b \1 \b
)
(?: [1-9] | [1-2] \d | 3 [0-1] ) # Unrolled-loop, match 1 to many numb's
(?: # in the number range 1-31
,
(?: [1-9] | [1-2] \d | 3 [0-1] )
)*
$ # EOS
var data = [
'2,4,6,7,1',
'2,2,6',
'2,30,16,3',
'2,',
'1,2,3,2',
'1,2,2,3',
'1,2,3,4,5,6,7,8'
];
data.forEach(function(str) {
document.write(str + ' gives ' + /^(?!.*(\b(?:[1-9]|[1-2]\d|3[0-1])\b).*\b\1\b)(?:[1-9]|[1-2]\d|3[0-1])(?:,(?:[1-9]|[1-2]\d|3[0-1]))*$/.test(str) + '<br/>');
});
I have created a pattern that can do this.
The pattern:^((?!(\d+),[^\n]*\b\2\b)([1-9]\b|[1-2]\d|3[0-1])(,(?1))?)$
A demo.
A short description.
^ - matches start of a line
(?!(\d+),[^\n]*\b\2\b) - Looks ahead to ensure the next number is not repeated
(\d+) - grab next number
,[^\n]* - a comma followed by anything but a new line
\b\2\b - The next number again repeated
([1-9]\b|[1-2]\d|3[0-1]) - Checks next number between 1-31
[1-9]\b - Checks for single digit. Boundary used so to prevent two digit numbers matching.
[1-2]\d - Checks for 10-29
3[0-1] - Checks for 30,31
(,(?1))?) If followed by comma recurse on main pattern to check if next number is repeated.
, - checks followed by acomma
(?1) - recurses on main pattern.
$ - End of line
Updated: Forgot to check 1-31
I totally agree that there are much better ways than regex to look for duplicates, but if you must do this as regex, here's a way (depending on your regex flavor).
See on regex101 (I have made it multiline and extended just for testing and readability).
^
(?!.*\b(\d+)\b.*\b\1\b)
(0?[1-9]|[12][0-9]|3[01])
(,(0?\d|[12][0-9]|3[01]))*
$
Explanation:
(?!.*\b(\d+)\b.*\b\1\b) is a negative lookahead to ensure there are no duplicates
(0?[1-9]|[12][0-9]|3[01]) matches the first number
(,(0?\d|[12][0-9]|3[01]))* matches any more
Note: updated to use word boundaries - based on answer from #sln
Related
I have a block of number characters separated by '=' and the number range can be always different on both sides.
Example: 12345678999999=654784651321, next time it could be: 4567894135=456789211
I need help with finding suitable regex which select me always numbers between first 6 and last 4 digits of left side of block and then all numbers after 7th digit of right side of block:
123456[][][][]9999=6547846[][][][][]
Is this somehow possible?
[0-9]{6}([0-9]*)[0-9]{4}=[0-9]{7}([0-9]*)
Assuming the difficulty isn't matching a continuous set of digits, but rather matches each digit seperately try:
(?:^\d{6}|=\d{7}|\G)(?=\d{5,8}=|\d*$)\K\d
See an online demo
(?: - Open non-capture group for alternation;
^\d{6} - Match start-line anchor followed by 6 digits;
| - Or;
=\d{7} - Match a literal '=' followed by exactly 7 digits;
| - Or;
\G - Assert position at end of previous match or start of string;
(?=\d{5,8}=|\d*$) - Positive lookahead to assert possition is followed by either 5-8 digits upto an '=' or 0+ (greedy) digits upto end-line anchor;
\K - Reset starting point of previous reported match;
\d - A single digit.
Alternatively, if you have an environment that supports zero-width lookbehind like JavaScript or PyPi's regex package in Python, try:
(?:(?=\d{5,8}=)(?<=\d{6})|(?<==\d{7,}))\d
See an online demo
(?: - Open non-capture group for alternation;
(?=\d{5,8}=)(?<=\d{6}) - Positive lookahead to assert position is followed by 5-8 digits and an '=' but also preceded by at least 6 digits;
| - Or;
(?<==\d{7,}) - Positive lookbehind to assert position is preceded by an '=' followed by 7+ digits;
\d - A single digit.
// 6 NOT number or =
// ||
// \/
/[0-9]{6}[^\=0-9]*\=[^\=0-9]*[0-9]{4}/
I have been trying but without success
I need a regular expression for validating numbers that could contain dots and commas,
the number should be positive and there should be max of two numbers after the comma
Valid cases would be:
1000 - valid
1,000 - valid
1,000.22 - valid
-2 not valid
1,000.233 not valid
0 not valid
1.00,22 - not valid
Language is javascript
let valid =["1000","1,000","1,000.22"];
let notValid = ["-2","1,000.233 ","0","1.00,22"];
let rge = /^[1-9]+\d*(,\d{3})*(\.\d{1,2})?$/;
for(let x of valid)
console.log(x," è valida? ",rge.test(x));
for(let x of notValid)
console.log(x," è valida? ",rge.test(x));
Above there is a possible solution in Javascript, you haven't specified the language.
\d are numbers in the range [0-9]
The full stop . is a metacharacter (it means any character), to refer to the character . you have to escape it thereby \.
+ means at least 1 or more times
* means 0 or more times
? means 0 or 1 time
{1,2} means match minimum 1 time, maximum 2 times
The starting ^ and final $ refer to a exact matching otherwise you could have a partial matching of the string
A few assumptions:
Invalid: '123456789.12' and '12345,123.12'
I think the following does what you are after:
^[1-9](?:\d*|\d{0,2}(?:,\d{3})*(?:\.\d\d?)?)$
See the online demo
^ - Start-line anchor.
[1-9] - A single digit in the range 1-9.
(?: - Open a non-capture group:
\d* - 0+ Digits to allow any integer.
| - Or:
\d{0,2} - Between 0 to 2 digits;
(?:,\d{3})* - Followed by a non-capture group to allow any 0+ times a comma followed by 3 digits.
(?:\.\d\d?)? - Followed by an optional non-capture group to allow up to two decimals.
)$ - Close non-capture group and match the end-line anchor.
Or, if you also want to allow any integer followed by decimals (e.g: '123456789.01') you may change this to:
^[1-9](?:\d*|\d{0,2}(?:,\d{3})*)(?:\.\d\d?)?$
I think this regex should do the trick:
[1-9][\d,]*(\.\d{1,2})?
[1-9] - matches one character between 1 and 9 at the beginning (required to not match 0)
[\d,]* - matches zero or more digits or commas
(\.\d{1,2})? - zero or one group of a dot and one or two digits
For testing regexes I do recommend https://regex101.com/
I have a method to extract number from a string using regex, like that:
def format
str = "R$ 10.000,00 + Benefits"
str.split(/[^\d]/).join
end
Its returns --> 1000000. I need to modfy regex to return 10000, removing zeros after comma.
You can use
str.gsub(/(?<=\d),\d+|\D/, '')
See the regex demo.
Regex details
(?<=\d),\d+ - a comma that is immediately preceded with a digit ((?<=\d) is a positive lookbehind) and then one or more digits
| - or
\D - any non-digit symbol
One important aspect is that you should order these alternatives like this, \D must be used as the last alternative. Else, \D can match a , and the solution won't work.
str = "R$ 10.000,00 R$1.200.000,03 R$ 0,09 R$ 4.00,10 R$ 3.30005,00 R$ 6.700 R$ 6, R$ 6,0 R$ 00,20 R$6,001 US$ 5.122,00 Benefits"
R = /(?:(?<=\bR\$)|(?<=\bR\$ ))(?:0|[1-9]\d{0,2}(?:\.\d{3})*),\d{2}(?!\d)/
str.scan(R).map { |s| s.delete('.') }
#=> ["10000,00", "1200000,03", "0,09"]
None of the following substrings match because they have invalid formats: "4.00,10", " 3.30005,00", "6.700", "6,", "6,0", "00,20", "6,001" and "5.122,00" (the last because it is not preceded by "$R" or "$R ".
The regular expression can be written in free-spacing mode (/x) to make it self-documenting.
R = /
(?: # begin non-capture group
(?<=\bR\$) # positive lookbehind asserts match is preceded by 'R$'
# that is preceded by a word break
| # or
(?<=\bR\$\ ) # positive lookbehind asserts match is preceded by 'R$ '
# that is preceded by a word break
) # end non-capture group
(?<= # begin negative lookbehind
$R[ ]) # asserts that match is preceded by a space
(?: # begin non-capture group
0 # match zero
| # or
[1-9] # match a digit other than zero
\d{0,2} # match 0-2 digits
(?:\.\d{3}) # match '.' followed by three digits in a non-capture group
* # execute preceding non-capture group 0+ times
) # end non-capture group
,\d{2} # match ',' followed by two digits
(?!\d) # negative lookahead asserts match is not followed by a digit
/x
Here is a slightly longer, but perhaps simpler and easier to understand solution. You can use it as an alternative to the excellent and concise answer by Wiktor Stribiżew, and the very thorough and complete answer by Cary Swoveland. Note that my answer may not work for some (more complex) strings, as mentioned in the comment by Cary below.
str = "R$ 10.000,00 + Benefits"
puts str.gsub(/^.*?(\d+[\d.]*).*$/, '\1').gsub(/[.]/, '')
# => 10000
Here gsub is applied to the input string twice:
gsub(/^.*?(\d+[\d.]*).*$/, '\1') : grab 10.000 part.
^ is the beginning of the string.
.*? is any character repeated 0 or more times, non-greedy (that is, minimum number of times).
(\d[\d.]*) is any digit followed by digits or literal dots (.). The parenthesis capture this and put into the first capture group (to be used later as '\1' as the replacement string).
.* is any character repeated 0 or more times, greedy (that is, as many as possible).
$ is the end of the string.
Thus, we replace the entire string with the first captured group: '\1', which is 10.000 here. Remember to use single quotes around \1, otherwise escape it twice like so: "\\1".
gsub(/[.]/, '') : remove all literal dots (.) in the string.
Note that this code does the expected replacements for a number of similar strings (but nothing fancier, such as leaves 001 as is):
['R$ 10.000,00 + Benefits',
'R$ 0,00 + Benefits',
'R$ .001,00 + Benefits',
'. 10.000,00 + Benefits',].each do |str|
puts [str, str.gsub(/^.*?(\d+[\d.]*).*$/, '\1').gsub(/[.]/, '')].join(" => ")
end
Output:
R$ 10.000,00 + Benefits => 10000
R$ 0,00 + Benefits => 0
R$ .001,00 + Benefits => 001
. 10.000,00 + Benefits => 10000
The following Regex checks for a number which starts with 6, 8 or 9 and has to be exactly 8 digits long.
/^(6|8|9)\d{7}$/
Now I want to accept one space in between digits as well, but don't know where to start.
For example both 61234567 and 6123 4567 should be allowed, but only the first one passes my current regex.
Can you help me create it?
You may use
^(?!.*(?:\s\d+){2})[689](?:\s?\d){7}$
See the regex demo
Details
^ - start of string
(?!.*(?:\s\d+){2}) - a negative lookahead that fails the match if, after any 0+ chars other than line break chars, as many as possible occurrences, there are two occurrences of a whitespaces followed with 1+ digits
[689] - 6, 7 or 9
(?:\s?\d){7} - seven occurrences of an optional whitespace followed with a single digit
$ - end of string.
To allow leadign/trailing whitespace, add \s? (1 or 0) or \s* (0 or more) right after ^ and before $.
To allow a single 1+ more whitespace chunk in the digit string, use
^(?!.*(?:\s+\d+){2})[689](?:\s*\d){7}$
See this regex demo.
You could use the regular expression
/^[689](?:\d{7}|(?=.{8}$)\d* \d+)$/
demo
We can make this self-documenting by writing it in free-spacing mode:
/
^ # match beginning of line
[689] # match '6', '8' or '9'
(?: # begin non-capture group
\d{7} # match 7 digits
| # or
(?=.{8}$) # require the remainder of the line to have 8 chars
\d*\ \d+ # match 0+ digits, a space, 1+ digits
) # end non-capture group
$ # match end of line
/x # free-spacing regex definition mode
I am trying enhance the given answer on another post:
^[1-9]\d*(?:\.[05])?$
Breakup:
^ # Start of input
[1-9] # match digit 1 to 9
\d* # match 0 or more of any digits
(?: # start of non-capturing group
\. # match a decimal
[05] # followed by digit 0 or 5
)? # end non-capturing group. (? makes this group optional)
$ # End of input
Only this time the regex needs to accept 0,5 or 0.5 and increments of 0,5 or 0.5
The number zero is the only one that can't be matched.
Already tried:
(?!0).{1}|^[1-9]\d*(?:(,|\.)[05])?$
and
[^0]|^[1-9]\d*(?:(,|\.)[05])?$
Can you help please?
You can use
^(?!0$)\d+(?:[,.][05])?$
See demo
This will match your required numbers and will exclude a 0-only number thanks to the look-ahead at the beginning.
Main changes:
\d+ - replaced [1-9]\d* to allow a 0 as the integer part
[,.] - replace \. to allow a comma as a decimal separator.
The lookahead adds a 0-number exception.
The lookahead can be enhanced to disallow 0.000-like input:
^(?!0+(?:[,.]0+)?$)\d+(?:[,.][05])?$
See another demo.
You can use this regex:
^(?:5|[1-9]\d*[05])(?:[,.][05])?$
RegEx Demo
This should do it:
^(?!0*$)0?\d*([,.]5)?$
See live demo.
This uses ^\d*([,.]5)?$ to match what you want, and uses ^(?!0*([,.]0*)?$) to exclude zero in all its forms, ie it won.t match 0, 000 etc