密码规则的这个正则表达式有什么问题

时间:2009-05-20 19:14:00

标签: regex

我正在尝试至少2个字母,至少2个非字母,以及至少6个字符的长度:

^.*(?=.{6,})(?=[a-zA-Z]*){2,}(?=[0-9@#$%^&+=]*){2,}.*$

但是在很多层面都错过了标记,但我不确定为什么。有什么建议吗?

3 个答案:

答案 0 :(得分:10)

虽然可以使用正则表达式完成此类测试,但进行非正则表达式检查可能更容易且更易于维护。实现这一目标的正则表达式相当复杂,有点难以理解。但是运行此测试的代码非常简单。例如,将以下方法作为您的需求的实现(语言C#)

public bool IsValid(string password) {
  // arg null check ommitted
  return password.Length >= 6 &&
         password.Where(Char.IsLetter).Count() > 2 &&
         password.Where(x => !Char.IsLetter(x)).Count() > 2;
}

答案 1 :(得分:2)

如果你真的想使用正则表达式,试试这个:

(?=.{6})(?=[^a-zA-Z]*[a-zA-Z][^a-zA-Z]*[a-zA-Z])(?=[^0-9@#$%^&+=]*[0-9@#$%^&+=][^0-9@#$%^&+=]*[0-9@#$%^&+=])^.+$

这匹配至少六个字符长((?=.{6,}))并且至少包含两个字母字符((?=[a-zA-Z][^a-zA-Z]*[a-zA-Z]))的任何内容,并且至少包含字符集{{1}的两个字符}([0-9@#$%^&+=])。

答案 2 :(得分:2)

要回答标题中的问题,这就是你的正则表达式出了什么问题:

首先,开头的.*(点星)消耗整个字符串。然后应用第一个前瞻(?=.{6,})并失败,因为匹配位置位于字符串的末尾。因此,正则表达式引擎开始回溯,通过一次向后移动匹配位置一个字符并重新应用前瞻来“收回”字符。当它取回六个字符时,第一个前瞻成功,下一个应用。

第二个前瞻是(?=[a-zA-Z]*),这意味着“在当前匹配位置,尝试匹配零个或多个ASCII字母。”匹配位置仍然是从字符串末尾开始的六个字符,但没关系;无论你应用它,前瞻总是会成功,因为它可以合法地匹配零个字符。此外,字母可以在字符串中的任何位置,因此前瞻必须容纳可能存在的任何非字母。

然后你有{2,}。它不是前瞻子表达式的一部分,因为它在括号之外。在那个位置,这意味着前瞻必须成功两次或更多次,这没有任何意义。如果成功一次,它将成功多次,因为它每次都在同一位置应用。将量词应用于前瞻(或任何其他零宽度断言,例如,lookbehind,word boundary,line anchors)时,某些正则表达式将其视为错误。大多数口味似乎忽略了量词。

然后你有另一个前瞻,总是会成功,另一个无用的量词。最后,最后的点星重新消耗了第一个点星必须放弃的六个字符。

我认为这就是你想要的:

^
(?=.{6})
(?=(?:[^A-Za-z]*[A-Za-z]){2})
(?=(?:[^0-9@#$%^&+=]*[0-9@#$%^&+=]){2})
.*$