Javascript Regex: Combinations of numbers and letters (i) except 1 - javascript

I'm writing a regex that should match the following predicate:
Combination of letters and numbers except number 1.
EG: TRS234, A2B3C4, 2A3B4C, 223GFG
I came up with this regex:
const regex = /^(?:[^1]+[a-z]|[a-z]+[^1])[a-z][^1]*$/i
It matches almost every case except for 2A3B4C, I've been doing lot of research but I'm not getting why it's not working for that particular case. Any help or suggestions to improve the regex will be greatly appreciated.
Thanks in advance!

Note that [^1] matches any char but 1, i.e. it also matches §, ł, etc. Also, [a-z][^1]* matches a letter followed with any 0+ chars other than 1, so the regex does not validate the expected string pattern.
You may use
const regex = /^(?:[02-9]+[a-z]|[a-z]+[02-9])[a-z02-9]*$/i
Or, a variation:
const regex = /^(?=[a-z02-9]*$)(?:\d+[a-z]|[a-z]+\d)[a-z\d]*$/i
See the regex demo and the regex graph:
Details
^ - start of string
(?:[02-9]+[a-z]|[a-z]+[02-9]) - either of the two:
[02-9]+[a-z] - 1 or more digits other than 1 followed with a letter
| - or
[a-z]+[02-9] - 1 or more letters followed with a digit other than 1
[a-z02-9]* - 0 or more letters or digits other than 1
$ - end of string.

Related

Using Regular Expression to validate the following requirement?

i am trying to validate a number exactly 15 digits with 5 digits group separated by "-" , ":" , "/", that should start with either 5 or 4 or 37, it also should not contain any characters.
It means
37344-37747-27744 - valid
40344-37747-27744 - valid
59344-37747-27744 - valid
37344:37747:27744 - valid
37344/37747/27744 - valid
87887-98734-83422 - Not valid
548aa:aa764:90887 - not valid
37759\29938\92093 - not valid
I was only able to go this far
\d{5}[-:\/]\d{5}[-:\/]\d{5}
Please help.
Try this one:
(((5|4)\d{4})|((37)\d{3}))[-:\/]\d{5}[-:\/]\d{5}
https://regex101.com/r/VvTq5P/1
Edit:
I would also add: \b at the beggining and at the end:
\b(((5|4)\d{4})|((37)\d{3}))[-:\/]\d{5}[-:\/]\d{5}\b
so nothing like:
12337344-37747-27744
can pass the test.
You could use look ahead (?=.) to first check if your string starts ^ with numbers 5|4|37 that is the requirement, here's full pattern:
^(?=5|4|37)\d{5}[-:\/]\d{5}[-:\/]\d{5}$
Demo here
If I understand correctly the regex is this:
((5|4)\d{4}|37\d{3})[-:\/]\d{5}[-:\/]\d{5}
Needs to be
4XXXX, 5XXXX or 37XXX
So I split it up to accept the 3 forms
((5|4)\d{4}|37\d{3})[-:\/]\d{5}[-:\/]\d{5}
(5|4)\d{4} - looks for a number that starts with either 5 or 4 and four digits afterward.
Then the or 37\d{3} looks for 37 and three digits afterward.
If the separators have to be the same:
^(?=37|[54])\d{5}([-:\/])\d{5}\1\d{5}$
Explanation
^ Start of string
(?=37|[54]) Positive lookahead, assert either 37 or 5 or 4 to the right
\d{5} Match 5 digits
([-:\/]) Capture group 1, match one of - : /
\d{5} Match 5 digits
\1 Backreference to match the same separator as in group 1
\d{5} Match 5 digits
$ End of string
See a regex101 demo.
const regex = /^(?=37|[54])\d{5}([-:\/])\d{5}\1\d{5}$/;
[
"37344-37747-27744",
"40344-37747-27744",
"59344-37747-27744",
"37344:37747:27744",
"37344/37747/27744",
"87887-98734-83422",
"548aa:aa764:90887",
"37759\\29938\\92093",
"37344-37747/27744",
"37344:37747-27744"
].forEach(s =>
console.log(`${s} --> ${regex.test(s)}`)
)
The pattern without a lookaround using an alternation:
^(?:37\d{3}|[54]\d{4})([-:\/])\d{5}\1\d{5}$
See a regex101 demo
const regex = /^(?:37\d{3}|[54]\d{4})([-:\/])\d{5}\1\d{5}$/;
[
"37344-37747-27744",
"40344-37747-27744",
"59344-37747-27744",
"37344:37747:27744",
"37344/37747/27744",
"87887-98734-83422",
"548aa:aa764:90887",
"37759\\29938\\92093",
"37344-37747/27744",
"37344:37747-27744"
].forEach(s =>
console.log(`${s} --> ${regex.test(s)}`)
)

Capturing after the nth occurrence of a string using regex

My test string:
/custom-heads/food-drinks/51374-easter-bunny-cake
I am trying to capture the number in the string. The constants in that string are the the number is always preceded by 3 /'s and followed by a -.
I am a regex noob and am struggling with this. I cobbled together (\/)(.*?)(-) and then figured I could get the last one programmatically, but I would really like to understand regex better and would love if someone could show me the regex to get the last occurrence of numbers between / and -.
Don't use regexes if possible, i reccomend you to read - https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/ blog post
To your question, its easier, faster, more bullet proof to get it using splits
const articleName = "/custom-heads/food-drinks/51374-easter-bunny-cake".split("/")[3]
// '51374-easter-bunny-cake'
const articleId = articleName.split("-")[0]
// '51374'
hope it helps
You may use this regex with a capture group:
^(?:[^\/]*\/){3}([^-]+)
Or in modern browsers you can use lookbehind assertion:
/(?<=^(?:[^\/]*\/){3})[^-]+/
RegEx Demo 1
RegEx Demo 2
RegEx Code:
^: Start
(?:[^\/]*\/){3}: Match 0 or more non-/ characters followed by a /. Repeat this group 3 times
([^-]+): Match 1+ of non-hyphen characters
Code:
const s = `/custom-heads/food-drinks/51374-easter-bunny-cake`;
const re = /^(?:[^\/]*\/){3}([^-]+)/;
console.log (s.match(re)[1]);
Use
const str = `/custom-heads/food-drinks/51374-easter-bunny-cake`
const p = /(?:\/[^\/]*){2}\/(\d+)-/
console.log(str.match(p)?.[1])
See regex proof.
EXPLANATION
Non-capturing group (?:\/[^\/]*){2}
{2} matches the previous token exactly 2 times
\/ matches the character / with index 4710 (2F16 or 578) literally (case sensitive)
Match a single character not present in the list below [^\/]
* matches the previous token between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\/ matches the character / with index 4710 (2F16 or 578) literally (case sensitive)
\/ matches the character / with index 4710 (2F16 or 578) literally (case sensitive)
1st Capturing Group (\d+)
\d matches a digit (equivalent to [0-9])
+ matches the previous token between one and unlimited times, as many times as possible, giving back as needed (greedy)
- matches the character - with index 4510 (2D16 or 558) literally (case sensitive)

How does the following code mean two consecutive numbers?

This is from an exercise on FCC beta and i can not understand how the following code means two consecutive numbers seeing how \D* means NOT 0 or more numbers and \d means number, so how does this accumulate to two numbers in a regexp?
let checkPass = /(?=\w{5,})(?=\D*\d)/;
This does not match two numbers. It doesn't really match anything except an empty string, as there is nothing preceding the lookup.
If you want to match two digits, you can do something like this:
(\d)(\d)
Or if you really want to do a positive lookup with the (?=\D*\d) section, you will have to do something like this:
\d(?=\D*\d)
This will match against the last digit which is followed by a bunch of non-digits and a single digit. A few examples (matched numbers highlighted):
2 hhebuehi3
^
245673
^^^^^
2v jugn45
^ ^
To also capture the second digit, you will have to put brackets around both numbers. Ie:
(\d)(?=\D*(\d))
Here it is in action.
In order to do what your original example wants, ie:
number
5+ \w characters
a non-number character
a number
... you will need to precede your original example with a \d character. This means that your lookups will actually match something which isn't just an empty string:
\d(?=\w{5,})(?=\D*\d)
IMPORTANT EDIT
After playing around a bit more with a JavaScript online console, I have worked out the problem with your original Regex.
This matches a string with 5 or more characters, including at least 1 number. This can match two numbers, but it can also match 1 number, 3 numbers, 12 numbers, etc. In order to match exactly two numbers in a string of 5-or-more characters, you should specify the number of digits you want in the second half of your lookup:
let regex = /(?=\w{5,})(?=\D*\d{2})/;
let string1 = "abcd2";
let regex1 = /(?=\w{5,})(?=\D*\d)/;
console.log("string 1 & regex 1: " + regex1.test(string1));
let regex2 = /(?=\w{5,})(?=\D*\d{2})/;
console.log("string 1 & regex 2: " + regex2.test(string1));
let string2 = "abcd23";
console.log("string 2 & regex 2: " + regex2.test(string2));
My original answer was about Regex in a vacuum and I glossed over the fact that you were using Regex in conjunction with JavaScript, which works a little differently when comparing Regex to a string. I still don't know why your original answer was supposed to match two numbers, but I hope this is a bit more helpful.
?= Positive lookahead
w{5,} matches any word character (equal to [a-zA-Z0-9_])
{5,}. matches between 5 and unlimited
\D* matches any character that\'s not a digit (equal to [^0-9])
* matches between zero and unlimited
\d matches a digit (equal to [0-9])
This expression is global - so tries to match all
You can always check your expression using regex101

split javascript string using a regexp to separate numbers from other characters

so for example:
"10.cm" ...becomes... [10,".cm"] or ["10",".cm"], either will do as I can work with a string once it's split up.
i tried
"10.cm".split(/[0-9]/|/[abc]/)
but it seems that i don't have such a great understanding of using regexp's
thanks
You may tokenize the string into digits and non-digits with /\d+|\D+/g regex:
var s = "10.cm";
console.log(s.match(/\d+|\D+/g));
Details:
\d+ - matches 1 or more digits
| - or
\D+ - matches 1 or more characters other than digits.
/\W/ Matches any non-word character. This includes spaces and punctuation, but not underscores. In this solution can be used /\W/ with split and join methods. You can separate numbers from other characters.
let s = "10.cm";
console.log(s.split(/\W/).join(" "));
output = 10 cm

How to match digit in middle of a string efficiently in javascript?

I have strings like
XXX-1234
XXXX-1234
XX - 4321
ABCDE - 4321
AB -5677
So there will be letters at the beginning. then there will be hyphen. and then 4 digits. Number of letters may vary but number of digits are same = 4
Now I need to match the first 2 positions from the digits. So I tried a long process.
temp_digit=mystring;
temp_digit=temp_digit.replace(/ /g,'');
temp_digit=temp_digit.split("-");
if(temp_digit[1].substring(0,2)=='12') {}
Now is there any process using regex / pattern matching so that I can do it in an efficient way. Something like string.match(regexp) I'm dumb in regex patterns. How can I find the first two digits from 4 digits from above strings ? Also it would be great it the solution can match digits without hyphens like XXX 1234 But this is optional.
Try a regular expression that finds at least one letter [a-zA-Z]+, followed by some space if necessary \s*, followed by a hyphen -, followed by some more space if necessary \s*. It then matches the first two digits \d{2} after the pattern.:
[a-zA-Z]+\s*-\s*(\d{2})
may vary but number of digits are same = 4
Now I need to match the first 2 positions from the digits.
Also it would be great it the solution can match digits without hyphens like XXX 1234 But this is optional.
Do you really need to check it starts with letters? How about matching ANY 4 digit number, and capturing only the first 2 digits?
Regex
/\b(\d{2})\d{2}\b/
Matches:
\b a word boundary
(\d{2}) 2 digits, captured in group 1, and assigned to match[1].
\d{2} 2 more digits (not captured).
\b a word boundary
Code
var regex = /\b(\d{2})\d{2}\b/;
var str = 'ABCDE 4321';
var result = str.match(regex)[1];
document.body.innerText += result;
If there are always 4 digits at the end, you can simply slice it:
str.trim().slice(-4,-2);
here's a jsfiddle with the example strings:
https://jsfiddle.net/mckinleymedia/6suffmmm/

Categories