Regex matching string containing at least x characters and x numbers

岁酱吖の 提交于 2020-01-30 06:34:46

问题


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)
  1. How to disallow any other characters except [a-zA-Z!@#$%^&+=]?
  2. 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 \Ds will match newline characters, which will cause problems)



来源:https://stackoverflow.com/questions/52414717/regex-matching-string-containing-at-least-x-characters-and-x-numbers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!