“combine” 2 regex with a logic or? - javascript

I have two patterns for javascript:
/^[A-z0-9]{10}$/ - string of exactly length of 10 of alphanumeric symbols.
and
/^\d+$/ - any number of at least length of one.
How to make the expression of OR string of 10 or any number?
var pattern = /^([A-z0-9]{10})|(\d+)$/;
doesn't work by some reason. It passes at lest
pattern.test("123kjhkjhkj33f"); // true
which is not number and not of length of 10 for A-z0-9 string.

Note that your ^([A-z0-9]{10})|(\d+)$ pattern matches 10 chars from the A-z0-9 ranges at the start of the string (the ^ only modifies the ([A-z0-9]{10}) part (the first alternative branch), or (|) 1 or more digits at the end of the stirng with (\d+)$ (the $ only modifies the (\d+) branch pattern.
Also note that the A-z is a typo, [A-z] does not only match ASCII letters.
You need to fix it as follows:
var pattern = /^(?:[A-Za-z0-9]{10}|\d+)$/;
or with the i modifier:
var pattern = /^(?:[a-z0-9]{10}|\d+)$/i;
See the regex demo.
Note that grouping is important here: the (?:...|...) makes the anchors apply to each of them appropriately.
Details
^ - start of string
(?: - a non-capturing alternation group:
[A-Za-z0-9]{10} - 10 alphanumeric chars
| - or
\d+ - 1 or more digits
) - end of the grouping construct
$ - end of string

Related

Regex must be in length range and contain letters and numbers

I want to write a regex that will find substrings of length 10-15 where all characters are [A-Z0-9] and it must contain at least 1 letter and one number (spaces are ok but not other special characters). Some examples:
ABABABABAB12345 should match
ABAB1234ABA32 should match
ABA BA BABAB12345 should match
1234567890987 should not match
ABCDEFGHIJK should not match
ABABAB%ABAB12?345 should not match
So far the best two candidates I have come up with are:
(?![A-Z]{10,15}|[0-9]{10,15})[0-9A-Z]{10,15} - this fails because if the string has 10 consecutive numbers/letters it will not match, even though the 15 character string has a mix (e.g ABABABABAB12345).
(?=.*[0-9])(?=.*[A-Z])([A-Z0-9]+){10,15 } - this fails because it will match 15 consecutive letters as long as there is a number later in the string (even though it is outside the match) and vice versa (e.g. 123456789098765 abcde will match 123456789098765).
(I need to do this in python and js)
If each string is on its own line, then you can use start/end anchors to construct the regex:
^(?=.*[0-9])(?=.*[A-Z])(?:\s*[A-Z0-9]\s*){10,15}$
^ - start of line
(?=.*[0-9]) - lookahead, must contain a number
(?=.*[A-Z]) - lookahead, must contain a letter
(?: - start a non-capturing group
\s*[A-Z0-9]\s* Contains a letter or number with optional whitespaace
) - end non-capturing group
{10,15} - Pattern occurs 10 to 15 times
$ - end of line
See a live example here: https://regex101.com/r/eWX2Qo/1
This doesn't account for ABA BA BABAB12345, but this still might help.
Based on what you're trying to match, it looks like you want there to be a mix.
What you can do is two lookaheads. One looking for a in the following 15 characters, and another looking for a letter in the same space. If this matches, then it looks for a group of numbers and letters of length 10 to 15.
(?=.{0,14}\d)(?=.{0,14}[A-Z])[A-Z\d]{10,15}
https://regex101.com/r/qw1Q0S/1
(?=.{0,14}\d) character 1 through 15 has to be a number
(?=.{0,14}[A-Z]) character 1 through 15 has to be a capital letter
[A-Z\d]{10,15} match 10 to 15 letters and numbers if the previous conditions are true
Edit with an improved answer:
To account for the spaces, you can tweak the above concept.
(?=(?:. *+){0,14}\d)(?=(?:. *+){0,14}[A-Z])(?:[A-Z\d] *){10,15}
Above, in the lookahead we were matching .{0,14}. . has been changed to (?:. *+), which is a non capturing group that matches . in addition to 0 or more spaces.
So putting it together:
Lookahead 1:
(?=(?:. *+){0,14}\d)
This matches 0,14 characters that may or may not be followed by spaces. This effectively ignoring spaces. This also uses a possessive quantifier ( *+) when matching spaces to prevent the engine from backtracking when spaces are matched. The pattern would work without the + modifier, but would more than double the steps taken to match on the example.
Lookahead 2:
(?=(?:. *+){0,14}[A-Z])
Same as lookahead 1, but now testing for a capital letter instead of a digit.
If lookahead 1 and lookahead 2 both match, then the engine will be left in a place where our matches can potentially be made.
Actual match:
(?:[A-Z\d] *){10,15}
This matches the capital letters and numbers, but now also 0 or more spaces. The only drawback being that the trailing space will be include in your match, although that's easily handled in post processing.
Edit:
All whitespace (\r, \n, \t and ) can be accounted for by using \s vs .
Depending on the amount of space that exists. the possessive quantifier is necessary to prevent catestrophic backtracking. This modification to the input using possessive quantifiers completes in 22,332 steps, while this one using the same input, but with a regular quantifier, fails match anything due to catastrophic backtracking .
It should be noted that the possessive quantifier *+ is not supported with javascript or python's builtin re module, but it is supported with python's regex module:
>>> import regex
>>> pattern = r'(?=(?:.\s*+){0,14}\d)(?=(?:.\s*+){0,14}[A-Z])(?:[A-Z\d]\s*){10,15}'
>>> regex.search(pattern, 'AAAAAAAAAA\n2')
<regex.Match object; span=(0, 12), match='AAAAAAAAAA\n2'>
>>>
Has the right stuff
function lfunko() {
let a = ["ABABABABAB12345","ABAB1234ABA32","ABA BA BABAB12345","1234567890987","ABCDEFGHIJK","ABABAB%ABAB12?345"];
let o = a.map((s,i) => {
let ll = s.split("").filter(s => s.match(/[A-Z]/)).length;
let ln = s.split("").filter(s => s.match(/[0-9]/)).length;
let ot = s.split("").filter(s => s.match(/[^A-Z0-9]/)).length;
let sum = ll + ln
return (ll > 1 && ln > 1 && sum > 9 && sum < 16 && ot == 0)? `${s} - TRUE`:`${s} - FALSE`;
});
console.log(JSON.stringify(o));
}
Execution log
11:18:20 PM Notice Execution started
11:18:21 PM Info ["ABABABABAB12345 - TRUE","ABAB1234ABA32 - TRUE","ABA BA BABAB12345 - FALSE","1234567890987 - FALSE","ABCDEFGHIJK - FALSE","ABABAB%ABAB12?345 - FALSE"]
11:18:21 PM Notice Execution completed
Your require of [A-Z0-9] does not include spaces so third example should be false.
Should be
ABABABABAB12345 should match
ABAB1234ABA32 should match
ABA BA BABAB12345 should not match has spaces
1234567890987 should not match
ABCDEFGHIJK should not match
ABABAB%ABAB12?345 should not match

Javascript Regular Expresion [duplicate]

I'm trying to write a RegExp to match only 8 digits, with one optional comma maybe hidden in-between the digits.
All of these should match:
12345678
12,45678
123456,8
Right now I have:
^[0-9,]{8}
but of course that erroneously matches 012,,,67
Example:
https://regex101.com/r/dX9aS9/1
I know optionals exist but don't understand how to keep the 8 digit length applying to the comma while also keeping the comma limited to 1.
Any tips would be appreciated, thanks!
To match 8 char string that can only contain digits and an optional comma in-between, you may use
^(?=.{8}$)\d+,?\d+$
See the regex demo
The lookahead will require the string to contain 8 chars. ,? will make matching a comma optional, and the + after \d will require at least 1 digit before and after an optional comma.
If you need to match a string that has 8 digits and an optional comma, you can use
^(?:(?=.{9}$)\d+,\d+|\d{8})$
See the regex demo
Actually, the string will have 9 characters in the string (if it has a comma), or just 8 - if there are only digits.
Explanation:
^ - start of string
(?:(?=.{9}$)\d+,\d+|\d{8}) - 2 alternatives:
(?=.{9}$)\d+,\d+ - 1+ digits followed with 1 comma followed with 1+ digits, and the whole string matched should be 9 char long (8 digits and 1 comma)
| - or
\d{8} - 8 digits
$ - end of string
See the Java code demo (note that with String#matches(), the ^ and $ anchors at the start and end of the pattern are redundant and can be omitted since the pattern is anchored by default when used with this method):
List<String> strs = Arrays.asList("0123,,678", "0123456", // bad
"01234,567", "01234567" // good
);
for (String str : strs)
System.out.println(str.matches("(?:(?=.{9}$)\\d+,\\d+|\\d{8})"));
NOTE FOR LEADING/TRAILING COMMAS:
You just need to replace + (match 1 or more occurrences) quantifiers to * (match 0 or more occurrences) in the first alternative branch to allow leading/trailing commas:
^(?:(?=.{9}$)\d*,\d*|\d{8})$
See this regex demo
You can use following regex if you want to let trailing comma:
^((\d,?){8})$
Demo
Otherwise use following one:
^((\d,?){8})(?<!,)$
Demo
(?<!,) is a negative-lookbehind.
/^(?!\d{0,6},\d{0,6},\d{0,6})(?=\d[\d,]{6}\d).{8}$/
I guess this cooperation of positive and negative look-ahead does just what's asked. If you remove the start and end delimiters and set the g flag then it will try to match the pattern along decimal strings longer than 8 characters as well.
Please try http://regexr.com/3d63m
Explanation: The negative look ahead (?!\d{0,6},\d{0,6},\d{0,6}) tries not to find any commas side by side if they have 6 or less decimal characters in between while the positive look ahead (?=\d[\d,]{6}\d) tries to find 6 decimal or comma characters in between two decimal characters. And the last .{8} selects 8 characters.

Regex to match optional parameter

I'm trying to write a regex to match an optional parameter at the end of a path.
I want to cover the first 4 paths but not the last one:
/main/sections/create-new
/main/sections/delete
/main/sections/
/main/sections
/main/sectionsextra
So far I've created this:
/\/main\/sections(\/)([a-zA-z]{1}[a-zA-z\-]{0,48}[a-zA-z]{1})?/g
This only finds the first 3. How can I make it match the first 4 cases?
You may match the string in question up the optional string starting with / with any 1 or or more chars other than / after it up to the end of the string:
\/main\/sections(?:\/[^\/]*)?$
^^^^^^^^^^^^^^
See the regex demo. If you really need to constrain the optional subpart to only consist of just letters and - with the - not allowed at the start/end (with length of 2+ chars), use
/\/main\/sections(?:\/[a-z][a-z-]{0,48}[a-z])?$/i
Or, to also allow 1 char subpart:
/\/main\/sections(?:\/[a-z](?:[a-z-]{0,48}[a-z])?)?$/i
Details
\/main\/sections - a literal substring /main/sections
(?:\/[^\/]*)? - an optional non-capturing group matching 1 or 0 occurrences of:
\/ - a / char
[^\/]* - a negated character class matching any 0+ chars other than /
$ - end of string.
JS demo:
var strs = ['/main/sections/create-new','/main/sections/delete','/main/sections/','/main/sections','/main/sectionsextra'];
var rx = /\/main\/sections(?:\/[^\/]*)?$/;
for (var s of strs) {
console.log(s, "=>", rx.test(s));
}

Replace last character of a matched string using regex

I am need to post-process lines in a file by replacing the last character of string matching a certain pattern.
The string in question is:
BRDA:2,1,0,0
I'd like to replace the last digit from 0 to 1. The second and third digits are variable, but the string will always start BRDA:2 that I want to affect.
I know I can match the entire string using regex like so
/BRDA:2,\d,\d,1
How would I get at that last digit for performing a replace on?
Thanks
You may match and capture the parts of the string with capturing groups to be able to restore those parts in the replacement result later with backreferences. What you need to replace/remove should be just matched.
So, use
var s = "BRDA:2,1,0,0"
s = s.replace(/(BRDA:2,\d+,\d+,)\d+/, "$11")
console.log(s)
If you need to match the whole string you also need to wrap the pattern with ^ and $:
s = s.replace(/^(BRDA:2,\d+,\d+,)\d+$/, "$11")
Details:
^ - a start of string anchor
(BRDA:2,\d+,\d+,) - Capturing group #1 matching:
BRDA:2, - a literal sunstring BRDA:2,
\d+ - 1 or more digits
, - a comma
\d+, - 1+ digits and a comma
\d+ - 1+ digits.
The replacement - $11 - is parsed by the JS regex engine as the $1 backreference to the value kept inside Group 1 and a 1 digit.

Regular expression for thousand separator without decimal point

I have regular expression which is working fine for decimal .
In below expression I want to remove decimal match to validate Integer
^-?(\d*)(,\d{1,3})*(?:[,]|([.]\d{0,2}))?$
Valid Match : 1,000 & 111, & -1000,00
Invalid Match : -,1 & 1,,,,
Use
^-?(?:\d{1,3}(?:,\d{3})*|\d+)?,?$
|---1---|
|---2-----|
|-3-|
The ^ asserts the position at the start of the string and $ asserts the position at the string end. -? matches an optional -. Part 1 matches 1 to 3 digits, Part 2 matches 0+ sequences of , followed with 3 digits, part 3 is an alternative to Part 1 & 2 combined and matches just 1+ digits. The whole number pattern is optional since the (?:...|...) is quantified with ? - one or zero occurrences.
The ,? before $ allows an optional comma at the end, delete if not required (you mentioned you need to allow 100, in the comments).
See the regex demo

Categories

Resources