正则表达式匹配字符串,至少包含x个字符和x个数字

时间:2018-09-19 21:56:15

标签: regex lookahead

我需要测试字符串是否符合以下规则:

  • 具有至少8个[a-zA-Z!@#$%^&+=]字符并且具有至少1个[0-9]数字或
  • 具有至少8个[0-9]数字,并且至少具有1个[a-zA-Z!@#$%^&+=]字符

到目前为止,我已经尝试过:

"^(?=(?=.*[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,}\$")

大多数情况下都可以,但是一种情况失败了:

"!abcdefgh1" --> matched (OK)
"{abcdefgh1" --> matched (NOT OK because character { shouldn't be allowed)
  1. 如何禁止除[a-zA-Z!@#$%^&+=]之外的其他任何字符?
  2. 是否可以用较短的方式编写该正则表达式?

谢谢

1 个答案:

答案 0 :(得分:1)

问题是您的.匹配任何字符。为了保持使用.来匹配通用字符的便利,并且还要求该字符串不包含允许的字符以外的其他字符,一个简单的调整将是在字符串的开头再次进行超前检查,以确保所有字符串末尾的字符是[a-zA-Z!@#$%^&+=][0-9],其他都没有。

还请注意,[0-9]简化为\d,这看起来有点更好:

^(?=[a-zA-Z!@#$%^&+=\d]{9,}$) <rest of your regex>

您还可以通过在组中重复大字符集来简化正则表达式,而不是手动将其写出8次。另外,如注释所述,在检查字符串是否具有足够的数字时,最好重复(?:\D*\d)而不是使用点,因为您知道您希望先行字符匹配非数字字符。

实际上,因为上面的初始查找确保了字符串仅包含数字和某些特定的非数字字符,而不是在匹配非数字时一次又一次重复长字符集[a-zA-Z!@#$%^&+=],所以您可以之所以使用\D,是因为初始的前瞻保证了非数字 将在该字符集中。

例如:

^(?=[a-zA-Z!@#$%^&+=\d]+$)(?:(?=\D*\d)(?=(?:\d*\D){8})|(?=(?:\D*\d){8})(?=\d*\D))

说明:

^(?=[a-zA-Z!@#$%^&+=\d]{9,}$)-确保字符串仅包含所需的字符(如果它们中至少有9个,则立即失败),然后在以下任意一个之间进行切换:

(?=\D*\d)(?=(?:\d*\D){8})-字符串至少包含一位数字和其他8个字符,或者

(?=(?:\D*\d){8})(?=\d*\D)-字符串包含至少8位数字和至少一个其他字符

https://regex101.com/r/18xtBw/2(要测试,一次只能输入一行-否则,\D会匹配换行符,这会引起问题)