Regular expression for no more than two repeated letters/digits - javascript

I have a requirement to handle a regular expression for no more than two of the same letters/digits in an XSL file.
no space
does not support special chars
support (a-z,A-Z,0-9)
require one of a-z
require one of 0-9
no more than 2 same letter/digits (i.e., BBB will fail, BB is accepted)
What I have so far
(?:[^a-zA-Z0-9]{1,2})

This regex will do it:
^(?!.*([A-Za-z0-9])\1{2})(?=.*[a-z])(?=.*\d)[A-Za-z0-9]+$
Here's the breakdown:
(?!.*([A-Za-z0-9])\1{2}) makes sure that none of the chars repeat more than twice in a row.
(?=.*[a-z]) requires at least one lowercase letter
(?=.*\d) requires at least one digit
[A-Za-z0-9]+ allows only letters and digits
EDIT :
removed an extraneous .* from the negative lookahead

(Partial solution) For matching the same character repeated 3 or more times consecutively, try:
([a-zA-Z0-9])\1{2,}
Sample matches (tested both here and here): AABBAA (no matches), AABBBAAA (matches BBB and AAA), ABABABABABABABA (no matches), ABCCCCCCCCCC (matches CCCCCCCCCC).

Does this one work for you?
/(\b(?:([A-Za-z0-9])(?!\2{2}))+\b)/
Try it out:
var regex = new RegExp(/(\b(?:([A-Za-z0-9])(?!\2{2}))+\b)/)
var tests = ['A1D3E', 'AAAA', 'AABAA', 'abccddeeff', 'abbbc', '1234']
for(test in tests) {
console.log(tests[test] + ' - ' + Boolean(tests[test].match(regex)))
}
Will output:
A1D3E - true
AAAA - false
AABAA - true
abccddeeff - true
abbbc - false
1234 - true

You may do this in 2 regexes:
/^(?=.*[a-z])(?=.*[0-9])[a-z0-9]+$/i This will assure that there is at least 1 digit and 1 letter while accepting only letters and digits (no space or special characters)
/([a-z0-9])\1{2,}/i If this one is matched, then there is a repeated character. Which means you should throw false.
Explanation:
First regex:
^ : match begin of line
(?=.*[a-z]) : check if there is at least one letter
(?=.*[0-9]) : check if there is at least one digit
[a-z0-9]+ : if the checks were true, then match only digits/letters one or more times
$ : match end of line
i : modifier, match case insensitive
Second regex:
([a-z0-9]) : match and group a digit or a letter
\1{2,} : match group 1 two or more times
i : modifier, match case insensitive

In response to a clarification, it seems that a single regular expression isn't strictly required. In that case I suggest you use several regular expressions or functions. My guess is, performance isn't a requirement, since usually these sorts of checks are done in response to user input. User input validation can take 100ms and still appear to be instant, and you can run a lot of code in 100ms.
For example, I personally would do a check for each of your conditions in a separate test. First, check for spaces. Second, check for at least one letter. Next, check for at least one number. Finally, look for any spans of three or more repeated characters.
Your code will be much easier to understand, and it will be much easier to modify the rules later (which, experience has shown, is almost certainly going to happen).
For example:
function do_validation(string) {
return (has_no_space(string) &&
has_no_special_char(string) &&
has_alpha(string) &&
has_digit(string) &&
! (has_repeating(string)))
I personally consider the above to be orders of magnitude easier to read than one complex regular expression. Plus, adding or removing a rule doesn't make you have to reimplement a complex regular expression (and thus, be required to re-test all possible combinations).

Related

How can I write the Javascript Regular Expression pattern to handle these conditions

In My exercise, I'm given a task to write a regular expression pattern that validates username input for storage into database.
Usernames can only use alpha-numeric characters.
The only numbers in the username have to be at the end. There can be zero or more of them at the end. Username cannot start with the number.
Username letters can be lowercase and uppercase.
Usernames have to be at least two characters long. A two-character username can only use alphabet letters as characters.
I succeeded to pass all tests except one
A1 is not supposed to match the patern
let userCheck = /^[A-Za-z]+\w\d*$/;
let result = userCheck.test(username);
You can use an alternation after ^[a-z] the first letter to require either [a-z]+ one or more letters followed by \d* any amount of digits | OR \d{2,} two or more digits up to $ end of the string.
let userCheck = /^[a-z](?:[a-z]+\d*|\d{2,})$/i;
See this demo at regex101 - Used with the i-flag (ignore case) to shorten [A-Za-z] to [a-z].
PS: Just updated my answer at some late cup of coffee ☕🌙. Had previously misread the question and removed my answer in meanwhile. I would also have missed the part with e.g. Z97 which I just read at the other answers comments. It's much more of a challenge than at first glance... obviously :)
Edit:
My first answer did not fully solve the task. This regex does:
^([A-Za-z]{2}|[A-Za-z]\w{2,})$
it matches either two characters, or one character followed by at least two characters and/or digits (\w == [A-Za-z0-9]). See the demo here: https://regex101.com/r/sh6UpX/1
First answer (incorrect)
This works for your description:
let userCheck = /^[A-Za-z]{2,}\d*$/;
let result = userCheck.test(username);
Let me explain what went wrong in your regex:
/^[A-Za-z]+\w\d*$/
You correctly match, that the first character is only a letter. The '+' however only ensures, that it is matched at least one time. If you want to match something an exact number of times, you can append '{x}' to your match-case. If you rather want to match a minimum and maximum amount of times, you can append '{min, max}'. In your case, you only have a lower limit (2 times), so the max stays empty and means unlimited times: {2,}
After your [2 - unlimited] letters, you want to have [0 - unlimited] numbers. '\w' also matches letters, so we can just remove it. The end of your regex was correct, as '\d' matches any digit, and '*' quantifies the previous match for the range [0 - unlimited].
I recommend using regex101.com for testing and developing regex patterns. You can test your strings and get very good documentation and explanation about all the tags. I added my regex with some example strings to this link:
https://regex101.com/r/qPmwhG/1
The strings that match will be highlighted, the others stay without highlighting.

Regular Expressions: Positive and Negative Lookahead Solution

I was doing Freecodecamp RegEx challange, which's about:
Use lookaheads in the pwRegex to match passwords that are greater than 5 characters long, do not begin with numbers, and have two consecutive digits
So far the solution I found passed all the tests was:
/^[a-z](?=\w{5,})(?=.*\d{2}\.)/i
However, when I tried
/^[a-z](?=\w{5,})(?=\D*\d{2,}\D*)/i
I failed the test trying to match astr1on11aut (but passed with astr11on1aut). So can someone help me explaining how ?=\D*\d{2,}\D* failed this test?
So can someone help me explaining how (?=\D*\d{2,}\D*) failed this
test?
Using \D matches any char except a digit, so from the start of the string you can not pass single digit to get to the 2 digits.
Explanation
astr1on11aut astr11on1aut
^ ^^
Can not pass 1 before reaching 11 Can match 2 digits first
Note
the expression could be shortened to (?=\D*\d{2}) as it does not matter if there are 2, 3 or more because 2 is the minimum and the \D* after is is optional.
the first expression ^[a-z](?=\w{5,})(?=.*\d{2}\.) can not match the example data because it expects to match a . literally after 2 digits.
Failed for the \d{2,}
Then let's have a look at the regexp match process
/^[a-z](?=\w{5,})
means start with [a-z], the length is at least 6, no problem.
(?=\D*\d{2,}\D*)
means the first letter should be followed by these parts:
[0 or more no-digit][2 or more digits][0 or more no-digits]
and lets have a look at the test case
astr1on11aut
// ^[a-z] match "a"
// length matchs
// [0 or more no-digit]: "str"
// d{2,} failed: only 1 digit
the ?= position lookahead means exact followed by.
The first regular expression is wrong, it should be
/^[a-z](?=\w{5,})(?=.*\d{2}.*)/i
When it comes to lookahead usage in regex, rememeber to anchor them all at the start of the pattern. See Lookarounds (Usually) Want to be Anchored. This will help you avoid a lot of issues when dealing with password regexps.
Now, let's see what requirements you have:
"are greater than 5 characters long" => (?=.{6}) (it requires any 6 chars other than lien break chars immediately to the right of the current location)
"do not begin with numbers" => (?!\d) (no digit allowed immediately to the right)
have two consecutive digits => (?=.*\d{2}) (any two digit chunk of text is required after any 0 or more chars other than line break chars as many as possible, immediately to the right of the current location).
So, what you may use is
^(?!\d)(?=.{6})(?=.*\d{2})
Note the most expensive part is placed at the end of the pattern so that it could fail quicker if the input is non-matching.
See the regex demo.

Javascript Password Generator how to ensure password meets criteria [duplicate]

What is the regex to make sure that a given string contains at least one character from each of the following categories.
Lowercase character
Uppercase character
Digit
Symbol
I know the patterns for individual sets namely [a-z], [A-Z], \d and _|[^\w] (I got them correct, didn't I?).
But how do I combine them to make sure that the string contains all of these in any order?
If you need one single regex, try:
(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)
A short explanation:
(?=.*[a-z]) // use positive look ahead to see if at least one lower case letter exists
(?=.*[A-Z]) // use positive look ahead to see if at least one upper case letter exists
(?=.*\d) // use positive look ahead to see if at least one digit exists
(?=.*\W) // use positive look ahead to see if at least one non-word character exists
And I agree with SilentGhost, \W might be a bit broad. I'd replace it with a character set like this: [-+_!##$%^&*.,?] (feel free to add more of course!)
Bart Kiers, your regex has a couple issues. The best way to do that is this:
(.*[a-z].*) // For lower cases
(.*[A-Z].*) // For upper cases
(.*\d.*) // For digits
(.*\W.*) // For symbols (non-word characters)
In this way you are searching no matter if at the beginning, at the end or at the middle. In your have I have a lot of troubles with complex passwords.
Bart Kiers solution is good but it misses rejecting strings having spaces and accepting strings having underscore (_) as a symbol.
Improving on the Bart Kiers solution, here's the regex:
(?=.*\d)(?=.*[a-z])(?=.*[A-Z])((?=.*\W)|(?=.*_))^[^ ]+$
A short explanation:
(?=.*[a-z]) // use positive look ahead to see if at least one lower case letter exists
(?=.*[A-Z]) // use positive look ahead to see if at least one upper case letter exists
(?=.*\d) // use positive look ahead to see if at least one digit exists
(?=.*\W) // use positive look ahead to see if at least one non-word character exists
(?=.*_) // use positive look ahead to see if at least one underscore exists
| // The Logical OR operator
^[^ ]+$ // Reject the strings having spaces in them.
Side note: You can try test cases on a regex expression here.
You can match those three groups separately, and make sure that they all present. Also, [^\w] seems a bit too broad, but if that's what you want you might want to replace it with \W.

Regular expression to include numeric only or character only or ignore first two conditions if alpha numeric

I wrote Regular expression for the below cases :
only numbers(length:4)
only alphabets(should contain vowel)
([0-9]{1,4})|((?=[a-z]*[aeiou])[a-z]*)
eg: 9987, tyde
How to add the below condition?
Ignore the first two cases if the string contains alphanumeric
characters.
eg: 9ty87
If I decypher well your question, I think your are looking for that:
a string with only digits and between one and four characters
a string with only letters with at least a vowel
a string with only letters and digits with at least one letter and one digit.
pattern:
/^(?:[0-9]{1,4}|[bcdfghj-np-tv-z]*[aeiou][a-z]*|[a-z]+[0-9][a-z0-9]*|[0-9]+[a-z][a-z0-9]*)$/i
or more factorized
/^(?:[0-9]{1,4}(?:[0-9]*[a-z][a-z0-9]*)?|[bcdfghj-np-tv-z]*(?:[aeiou][a-z]*|[a-z]+[0-9][a-z0-9]*))$/i
It is a simple alternation (I don't think you need something more complicated). So only one of the branches will succeed.
Note that anchors ^ and $ are essential for this kind of task to ensure that whole string is taken in account.

Please explain some Javascript Regular Expressions

I'm learning Javascript via an online tutorial, but nowhere on that website or any other I googled for was the jumble of symbols explained that makes up a regular expression.
Check if all numbers: /^[0-9]+$/
Check if all letters: /^[a-zA-Z]+$/
And the hardest one:
Validate Email: /^[\w-.+]+\#[a-zA-Z0-9.-]+.[a-zA-z0-9]{2,4}$/
What do all the slashes and dollar signs and brackets mean? Please explain.
(By the way, what languages are required to create a flexible website? I know a bit of Javascript and wanna learn jQuery and PHP. Anything else needed?)
Thanks.
There are already a number of good sites that explain regular expressions so I'll just dive a bit into how each of the specific examples you gave translate.
Check if all numbers: ^ anchors the start of the expression (e.g. start at the beginning of the text). Without it a match could be found anywhere. [0-9] finds the characters in that character class (e.g. the numbers 0-9). The + after the character class just means "one or more". The ending $ anchors the end of the text (e.g. the match should run to the end of the input). So if you put that together, that regular expression would allow for only 1 or more numbers in a string. Note that the anchors are important as without them it might match something like "foo123bar".
Check if all letters: Pretty much the same as above but the character classes are different. In this example the character class [a-zA-Z] represents all lowercase and uppercase characters.
The last one actually isn't any more difficult than the other two it's just longer. This answer is getting quite long so I'll just explain the new symbols. A \w in a character class will match word characters (which are defined per regex implementation but are generally 0-9a-zA-Z_ at least). The backslash before the # escapes the # so that it isn't seen as a token in the regex. A period will match any character so .+ will match one or more of any character (e.g. a, 1, Z, 1a, etc). The last part of the regex ({2,4}) defines an interval expression. This means that it can match a minimum of 2 of the thing that precedes it, and a maximum of 4.
Hope you got something out of the above.
There is an awesome explanation of regular expressions at http://www.regular-expressions.info/ including notes on language and implementation specifics.
Let me explain:
Check if all numbers: /^[0-9]+$/
So, first thing we see is the "/" at the beginning and the end. This is a deliminator, and only serves to show the beginning and end of the regular expression.
Next, we have a "^", this means the beginning of the string. [0-9] means a number from 0-9. + is a modifier, which modifies the term in front of it, in this case, it means you can have one or more of something, so you can have one or more numbers from 0-9.
Finally, we end with "$", which is the opposite of "^", and means the end of the string. So put that all together and it basically makes sure that inbetween the start and end of the string, there can be any number of digits from 0-9.
Check if all letters: /^[a-zA-Z]+$/
We notice this is very similar, but instead of checking for numbers 0-9, it checks for letters a-z (lowercase) and A-Z (uppercase).
And the hardest one:
Validate Email: /^[\w-.+]+\#[a-zA-Z0-9.-]+.[a-zA-z0-9]{2,4}$/
"\w" means that it is a word, in this case we can have any number of letters or numbers, as well as the period means that it can be pretty much any character.
The new thing here is escape characters. Many symbols cannot be used without escaping them by placing a slash in front, as is the case with "\#". This means it is looking directly for the symbol "#".
Now it looks for letters and symbols, a period (this one seems incorrect, it should be escaping the period too, though it will still work, since an unescaped period will make any symbol). Numbers inside {} mean that there is inbetween this many terms in the previous term, so of the [a-zA-Z0-9], there should be 2-4 characters (this part here is the website domain, such as .com, .ca, or .info). Note there's another error in this one here, the [a-zA-z0-9] should be [a-zA-Z0-9] (capital Z).
Oh, and check out that site listed above, it is a great set of tutorials too.
Regular Expressions is a complex beast and, as already pointed out, there are quite a few guides off of google you can go read.
To answer the OP questions:
Check if all numbers: /^[0-9]+$/
regexps here are all delimated with //, much like strings are quoted with '' or "".
^ means start of string or line (depending on what options you have about multiline matching)
[...] are called character classes. Anything in [] is a list of single matching characters at that position in this case 0-9. The minus sign has a special meaning of "sequence of characters between". So [0-9] means "one of 0123456789".
+ means "1 or more" of the preceeding match (in this case [0-9]) so one or more numbers
$ means end of string/line match.
So in summary find any string that contains only numbers, i.e '0123a' will not match as [0-9]+ fails to match a before $).
Check if all letters: /^[a-zA-Z]+$/
Hopefully [A-Za-z] makes sense now (A-Z = ABCDEF...XYZ and a-z abcdef...xyz)
Validate Email: /^[\w-.+]+\#[a-zA-Z0-9.-]+.[a-zA-z0-9]{2,4}$/
Not all regexp parses know the \w sequence. Javascript, java and perl I know do support it.
I have already have covered '/^ at the beginning, for this [] match we are looking for
\w - . and +. I think that regexp is incorrect. Either the minus sign should be escaped with \ or it should be at the end of the [] (i.e [\w+.-]). But that is an aside they are basically attempting to allow anything of abcdefghijklmnopqrstuvwxyz01234567890-.+
so fred.smith-foo+wee#mymail.com will match but fred.smith%foo+wee#mymail.com wont (the % is not matched by [\w.+-]).
\# is the litteral atsil sign (it is escaped as perl expands # an array variable reference)
[a-zA-Z0-9.-]+ is the same as [\w.-]+. Very much like the user part of the match, but does not match +. So this matches foo.com. and google.co. but not my+foo.com or my***domain.co.
. means match any one character. This again is incorrect as fred#foo%com will match as . matches %*^%$£! etc. This should of been written as \.
The last character class [a-zA-z0-9]{2,4} looks for between 2 3 or 4 of the a-zA-Z0-9 specified in the character class (much like + looks for "1 more more" {2,4} means at least 2 with a maximum of 4 of the preceeding match. So 'foo' matches, '11' matches, '11111' does not match and 'information' does not.
The "tweaked" regexp should be:
/^[\w.+-]+\#[a-zA-Z0-9.-]+\.[a-zA-z0-9]{2,4}$/
I'm not doing a tutorial on RegEx's, that's been done really well already, but here are what your expressions mean.
/^<something>$/ String begins, has something in the middle, and then immediately ends.
/^foo$/.test('foo'); // true
/^foo$/.test('fool'); // false
/^foo$/.test('afoo'); // false
+ One or more of something:
/a+/.test('cot');//false
/a+/.test('cat');//true
/a+/.test('caaaaaaaaaaaat');//true
[<something>] Include any characters found between the brackets. (includes ranges like 0-9, a-z, and A-Z, as well as special codes like \w for 0-9a-zA-Z_-
/^[0-9]+/.test('f00')//false
/^[0-9]+/.test('000')//true
{x,y} between X and Y occurrences
/^[0-9]{1,2}$/.test('12');// true
/^[0-9]{1,2}$/.test('1');// true
/^[0-9]{1,2}$/.test('d');// false
/^[0-9]{1,2}$/.test('124');// false
So, that should cover everything, but for good measure:
/^[\w-.+]+\#[a-zA-Z0-9.-]+.[a-zA-z0-9]{2,4}$/
Begins with at least character from \w, -, +, or .. Followed by an #, followed by at least one in the set a-zA-Z0-9.- followed by one character of anything (. means anything, they meant \.), followed by 2-4 characters of a-zA-z0-9
As a side note, this regular expression to check emails is not only dated, but it is very, very, very incorrect.

Categories

Resources