Reputation: 95
I have a requirement to test if string matches following rules:
[a-zA-Z!@#$%^&+=]
characters and has at least 1 [0-9]
number OR[0-9]
numbers and has at least 1 [a-zA-Z!@#$%^&+=]
characterSo far I tried this:
"^(?=(?=.*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=].*[a-zA-Z!@#$%^&+=])(?=.*[0-9])|(?=.*[0-9].*[0-9].*[0-9].*[0-9].*[0-9].*[0-9].*[0-9].*[0-9])(?=.*[a-zA-Z!@#$%^&+=])).{8,}\$")
It mostly works ok, but one scenario is failing:
"!abcdefgh1" --> matched (OK)
"{abcdefgh1" --> matched (NOT OK because character { shouldn't be allowed)
[a-zA-Z!@#$%^&+=]
?Thanks
Upvotes: 2
Views: 5214
Reputation: 370789
The problem is that your .
s are matching any character. To keep the convenience of using .
to match a generic character but also require that the string doesn't contain any characters other than what's allowed, a simple tweak would be another lookahead at the beginning of the string to ensure that all characters before the end of the string are [a-zA-Z!@#$%^&+=]
or [0-9]
, nothing else.
Also note that [0-9]
simplifies to \d
, which is a bit nicer to look at:
^(?=[a-zA-Z!@#$%^&+=\d]{9,}$) <rest of your regex>
You can also simplify your regex by repeating the big character set in a group, when possible, rather than writing it out manually 8 times. Also, as comment notes, when checking whether a string has enough digits, better to repeat (?:\D*\d)
rather than using a dot, because you know that you want the antecedent to match non-digit characters.
Actually, because the initial lookahead above ensures that the string contains only digits and those certain non-digit characters, rather than repeating the long character set [a-zA-Z!@#$%^&+=]
again and again when matching a non-digit, you can just use \D
, since the initial lookahead guarantees that non-digits will be within that character set.
For example:
^(?=[a-zA-Z!@#$%^&+=\d]+$)(?:(?=\D*\d)(?=(?:\d*\D){8})|(?=(?:\D*\d){8})(?=\d*\D))
Explanation:
^(?=[a-zA-Z!@#$%^&+=\d]{9,}$)
- ensure string contains only desired characters (fail immediately if there are not at least 9 of them), then alternate between either:
(?=\D*\d)(?=(?:\d*\D){8})
- string contains at least one digit, and 8 other characters, or
(?=(?:\D*\d){8})(?=\d*\D)
- string contains at least 8 digits, and at least one of the other characters
https://regex101.com/r/18xtBw/2 (to test, input only one line at a time - otherwise, the \D
s will match newline characters, which will cause problems)
Upvotes: 1