以下约束的正则表达式是什么?

时间:2011-05-26 05:45:20

标签: c# .net regex validation

我想要一个密码字符串的正则表达式,其中至少包含以下四种字符中的三种:

  • 英文小写字母(a到z)。
  • 英文大写字符(通过Z)。
  • 基数为10位(0到9)。
  • 非字母数字字符(例如!,$,#,%)。

至少应包含8个字符。

5 个答案:

答案 0 :(得分:10)

鉴于这些要求可能产生的怪物 a ,我怀疑你实际上会更好地做这个多次检查,比如(伪-code):

def check_password (s):
    if len(s) < 8:
        return false
    rules_followed = 0
    if match (s, "[a-z]") rules_followed++;
    if match (s, "[A-Z]") rules_followed++;
    if match (s, "[0-9]") rules_followed++;
    if match (s, "[!$#%]") rules_followed++;  # et cetera
    if rules_followed < 3:
        return false
    return true

当其他人必须维护您的代码时(或者即使必须在六个月后维护它),这可能更具可读性。

现在我意识到这可能并不总是可能的(例如,您可能会遇到只允许一个正则表达式进行验证的框架)。

但是,如果 可能,我强烈建议你考虑一下。您应该始终尝试优化的第一个是可读性。


a 你要么最终得到其中一个大规模的前瞻性正则表达式,要么最终包含由|分隔的十六种排序可能性。

这些都不像简单的代码段那样高效或可读。

答案 1 :(得分:3)

首先,这是paxdiablo代码的C#翻译:

public bool Validate(string input)
{
    if (input == null || input.Length < 8)
        return false;
    int counter = 0;
    if (input.Any(Char.IsLower)) counter++;
    if (input.Any(Char.IsUpper)) counter++;
    if (input.Any(Char.IsDigit)) counter++;
    if (input.Any(c => Char.IsPunctuation(c) || Char.IsSymbol(c))) counter++;
    return counter >= 3;
}

如果您坚持使用正则表达式,则可以使用与Fun With .NET Regex Balancing Groups上类似的模式:

^
(?=.*[a-z](?<Counter>))?
(?=.*[A-Z](?<Counter>))?
(?=.*[0-9](?<Counter>))?
(?=.*[^a-zA-Z0-9](?<Counter>))?
(?<-Counter>){3}   # check we've had at least 3 groups
.{8}

您也可以允许Unicode classes

^
(?=.*\p{Ll}(?<Counter>))?
(?=.*\p{Lu}(?<Counter>))?
(?=.*\p{Nd}(?<Counter>))?
(?=.*[\p{S}\p{P}](?<Counter>))?
(?<-Counter>){3}
.{8}

答案 2 :(得分:2)

扩展了正则表达式的PCRE版本:

/^(?:
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  )
  \S{8,}              # at least 8 non-spaces
$/x

答案 3 :(得分:1)

组合学并不是那么糟糕 - 只有四种方法可以选择四种可能性中的三种;您可以在正则表达式的开头测试具有前瞻性的那些,然后检查实际匹配的八个字符:

^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*\d)|(?=.*[A-Z])(?=.*[a-z])(?=.*[_\W])|(?=.*[A-Z])(?=.*\d)(?=.*[_\W])|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}

(锚定是为了在失败时提高效率,没有它就会有效。)

密码可能无关紧要,但上述版本可能会对同一类型的字符多次查看整个字符串,尤其是失败时。您可能会以这样的方式考虑它,但代价是可读性:

^(?:(?=.*[A-Z])(?:(?=.*[a-z])(?:(?=.*\d)|(?=.*[_\W]))|(?=.*\d)(?=.*[_\W]))|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}

答案 4 :(得分:0)

正确回答我的问题:

正则表达式:

^((= [\ d])(= [AZ])(= [AZ])|??????(= [AZ])(= [AZ])(= [^ \ W \ d \ S])|(= [\ d])(= [AZ])(= [^ \ W \ d \ S])|????(= [\ d])(?=。[AZ])(?=。[^ \ W \ d \ S]))。{8,30} $

感谢。