问题
I have a requirement to test if string matches following rules:
- Has at least 8
[a-zA-Z!@#$%^&+=]
characters and has at least 1[0-9]
number OR - Has at least 8
[0-9]
numbers and has at least 1[a-zA-Z!@#$%^&+=]
character
So 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)
- How to disallow any other characters except
[a-zA-Z!@#$%^&+=]
? - Is it possible to write that regex in shorter way?
Thanks
回答1:
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)
来源:https://stackoverflow.com/questions/52414717/regex-matching-string-containing-at-least-x-characters-and-x-numbers