Skip to main content
 首页 » 编程设计

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

2024年02月01日27me-sa

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

这些是条件:

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

这是我的尝试:

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

我知道满足上述条件还差得很远。所以请任何人修改这个正则表达式,使其满足上述所有条件。

提前致谢。

请您参考如下方法:

其他人已经为您建议了正则表达式的答案,也许这是您问题的不可动摇的约束。但是,这段 C# 可以满足您的要求,并且与正则表达式的不同之处在于它的可读性要高得多。我希望初级程序员能够阅读和理解它(而且修改它也更容易,比如说,不返回 false 但成功时返回 null 和一个描述密码失败的字符串)。它还在 O(n) 中运行(考虑到您的典型密码将是 << 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; 
} 

在您开始认为我已经对您进行了全面测试之前,您可以立即查看这段代码,每条规则都是自记录的。很容易修改。易于维护。所有规则都是相互隔离的,如果您选择对谓词使用静态方法而不是 lambda,您可以轻松地对每个规则单独进行单元测试。

运行这段代码:

    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