【问题标题】:what's wrong with this regex for password rules这个密码规则的正则表达式有什么问题
【发布时间】:2009-05-21 10:42:53
【问题描述】:

我正在尝试至少 2 个字母、至少 2 个非字母和至少 6 个字符的长度:

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

但这在很多层面上都没有达到目标,但我不知道为什么。有什么建议吗?

【问题讨论】:

  • 未达标是什么意思?
  • 顺便说一句,如果您确实使用正则表达式,为什么不使用 [^a-zA-Z] 来表示非字符。

标签: regex


【解决方案1】:

虽然可以使用正则表达式完成此类测试,但进行非正则表达式检查可能更容易且更易于维护。实现这一点的正则表达式相当复杂并且有点不可读。但是运行这个测试的代码是相当直接的。例如,将以下方法作为您的要求的实现(语言 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;
}

【讨论】:

  • 比任何单一的正则表达式都清晰得多。
  • 我同意。虽然您可以将其压缩为一行正则表达式,但请考虑一下您需要多长时间才能做到这一点,以及您将来更改/调试它需要多长时间。
  • 不可否认,非正则表达式选项可能会更好,但我的任务是“按你说的做”——我怀疑这个表达式将插入到 RegularExpressionValidator 控件中网络应用程序。我们这里有一句话“就是这样”
  • @Ralph 发生这种情况时真的很糟糕。您是否可以对同一个字符串进行多次正则表达式传递?这在 3 个简短的正则表达式中是非常可行的。一个巨大的正则表达式就是那个巨人。您必须尝试的排列数量非常多。
【解决方案2】:

要回答标题中的问题,您的正则表达式有什么问题:

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

第二个lookahead是(?=[a-zA-Z]*),意思是“在当前匹配位置,尝试匹配零个或多个ASCII字母”。匹配位置距离字符串末尾还有六个字符,但这没关系;无论您应用它,前瞻总是会成功,因为它可以合法地匹配零个字符。此外,字母可以在字符串中的任何位置,因此前瞻必须适应可能存在的任何中间非字母。

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

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

我认为这就是你想要的:

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

【讨论】:

  • 感谢您抽出宝贵的时间,不仅提供了一个正常工作的 RegEx,而且还详细解释了第一个问题的问题(正如您所指出的,这实际上是问题所在)
【解决方案3】:

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

(?=.{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])) 并且包含至少两个字符集 [0-9@#$%^&+=] ((?=[0-9@#$%^&+=][^0-9@#$%^&+=]*[0-9@#$%^&+=])) 的字符.

【讨论】:

  • 一个较短的正则表达式,其作用几乎相同:^(?=.{6}(?=.*[a-zA-Z].*[a-zA-Z]) .*[0-9@#$%^&+=].*[0-9@#$%^&+=]
  • 但由于不必要的回溯,效率较低。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多