密码验证的正则表达式C#

时间:2014-02-13 17:02:20

标签: c# regex

我想在c#中使用正则表达式验证密码。

以下是条件:

  1. 不应以数字或特殊字符开头
  2. 不应以特殊字符结尾
  3. 必须至少包含一次这三个中的任何一个('@','#','_'),不允许使用其他特殊字符。
  4. 必须至少包含一个字母
  5. 必须至少包含一位数字
  6. 长度应至少为8个字符
  7. 这是我的尝试:

    ^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#_])
    

    我知道它甚至不能满足上述条件。所以,任何人都可以修改这个正则表达式,以满足上述所有条件。

    提前致谢。

3 个答案:

答案 0 :(得分:4)

其他人已经为你提出了正则表达式的答案,也许这是你问题的不可动摇的约束。但是,这个C#块做了你所要求的,并且与正则表达式的不同之处在于它更具可读性。我希望初级程序员能够阅读并理解它(并且更容易将其修改为,例如,不返回false但成功时返回null,以及描述密码失败的字符串)。它也在O(n)中运行(考虑到您的典型密码将<&lt; <100个字符,这是一个小问题。

private const int kMinimumLength = 8;
private static string _specialChars = "@#_";
private static bool IsSpecialChar(char c) { return _specialChars.IndexOf(c) >= 0; }
private static bool IsValidPasswordChar(char c) { return IsSpecialChar(c) || Char.IsLetterOrDigit(c); }

public static bool IsPasswordValid(string password)
{
    if (password == null || password.Length < kMinimumLength || IsSpecial(password[0])
        || IsSpecial(password[password.Length - 1]))
             return false;
    bool hasLetter = false, hasDigit = false;
    int specials = 0;
    foreach (char c in password)
    {
       hasDigit = hasDigit || Char.IsDigit(c);
       hasLetter = hasLetter || Char.IsLetter(c);
       specials += IsSpecialChar(c) ? 1 : 0;
       if (!IsValidPasswordChar(c)) return false;
    }
    return hasDigit && hasLetter && specials > 1;
}

现在,如果您考虑这个过程并理解在这样一个小问题域中,您可能会因为可读性而做得更好:

public class Rule {
    public Func<string, bool> Predicate { get; set; }
    public string Description { get; set; }
}

private List<Rule> rules = new List<Rule>() {
    new Rule(){ Predicate = (s => s != null),
      Description = "Password must not be null" },
    new Rule(){ Predicate = (s => s.Length >= kMinimumLength ),
      Description = "Password must have at least " + kMinimumLength + " characters." },
    new Rule(){ Predicate = (s => s.Count(c => IsSpecialChar(c)) >= 1),
      Description = "Password must contain at least one of " + _specialChars },
    new Rule(){ Predicate = (s => !IsSpecialChar(s[0]) && !IsSpecialChar(s[s.Length - 1])),
      Description = "Password must not start or end with " + _specialChars },
    new Rule(){ Predicate = (s => s.Count(c => Char.IsLetter(c)) > 0),
      Description = "Password must contain at least one letter." },
    new Rule(){ Predicate = (s => s.Count(c => Char.IsDigit(c)) > 0),
      Description = "Password must contain at least one digit." },
    new Rule(){ Predicate = (s =>s.Count(c => !IsValidPasswordChar(c)) == 0),
      Description = "Password must contain letters, digits, or one of " + _specialChars }
}

public bool IsPasswordValid(string s, ref string failureReason)
{
    foreach (Rule r in rules) {
        if (!r.Predicate(s)) {
          failureReason = r.Description;
          return false;
        }
    }
    return true;
}

在你开始认为我已经完全了解你之前,你可以立即查看这些代码,每条规则都是自我记录的。它很容易修改。它易于维护。所有规则都是相互隔离的,如果你选择使用静态方法代替lambdas,你可以轻松地单独测试每个规则。

运行此代码:

    static void Main(string[] args)
    {
        string reason = null;
        if (!IsPasswordValid(null, ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("aaaaaaaa", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("_aaaaaaa", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("aaaaaaa_", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("1aaa!aaa", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("11111111", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("a1a1a1a1", ref reason)) Console.WriteLine(reason);
        if (!IsPasswordValid("a1a1@1a1", ref reason)) Console.WriteLine(reason);

        StringBuilder sb = new StringBuilder();
        sb.Append('a');
        for (int i = 0; i < 1000000; i++) { sb.Append('@'); }
        sb.Append('a');
        sb.Append('1');
        string pass = sb.ToString();
        long ticks = Environment.TickCount;
        if (IsPasswordValid(pass, ref reason)) Console.WriteLine("Valid.");
        long endticks = Environment.TickCount;
        Console.WriteLine("Time elapsed: " + (endticks - ticks));
    }

给出:

Password must not be null
Password must have at least 8 characters.
Password must contain at least one of @#_
Password must not start or end with @#_
Password must not start or end with @#_
Password must contain at least one of @#_
Password must contain at least one of @#_
Password must contain at least one of @#_
Valid.
Time elapsed: 62

因此,如果您担心性能问题,可以在62毫秒内检查1Mb密码(在我的机器上,这非常强大)。

tl; dr - “有些人在遇到问题时会想:”我知道,我会使用正则表达式。“现在他们有两个问题。” - Jamie Zawinksi

答案 1 :(得分:1)

给它一个旋转

^(?i)(?=.*[a-z])(?=.*[0-9])(?=.*[@#_])[a-z][a-z0-9@#_]{6,}[a-z0-9]$

符合您的规格我相信。从你当前的正则表达式的外观,你将能够理解它,但如果没有评论和不解释。

答案 2 :(得分:0)

^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[@#_])[a-zA-Z][\w@#]{6,}[a-zA-Z0-9]$