【问题标题】:Regular expression to check if password is "8 characters including 1 uppercase letter, 1 special character, alphanumeric characters"检查密码是否为“8个字符,包括1个大写字母、1个特殊字符、字母数字字符”的正则表达式
【发布时间】:2012-03-17 16:28:48
【问题描述】:

我想要一个正则表达式来检查

密码必须是八个字符,包括一个大写字母、一个特殊字符和一个字母数字字符。

这是我的验证表达式,它适用于八个字符,包括一个大写字母、一个小写字母和一个数字或特殊字符。

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

密码必须是八个字符,包括一个大写字母、一个特殊字符和字母数字字符,我该如何编写?

【问题讨论】:

  • 为什么需要正则表达式?符合您要求的完整正则表达式将非常冗长和复杂。用 C# 代码编写约束更容易。
  • 您是否考虑过检查强密码,而不是检查密码是否符合某些不完美的强密码代理规则?有很多库和程序在输入密码时会决定其强度。
  • 您需要确切一个大写/特殊字符还是至少一个?
  • 根据用户的要求,您的意思是您的用户正在口述实施细节吗?那么,也许他们应该自己编写代码。老实说,我认为如果您只是创建计数器并逐个检查每个字符,并为每个匹配规则的字符增加适当的计数器,那么维护和理解会更容易。从技术的角度来看,它不会给任何人留下深刻印象,但为什么要用容易出错且难以更新的东西使事情复杂化呢?

标签: c# regex


【解决方案1】:

您所追求的正则表达式很可能会很大,维护起来简直就是一场噩梦,尤其是对于那些不太熟悉正则表达式的人来说。

我认为分解你的正则表达式并一次做一点会更容易。可能需要做更多的工作,但我很确定维护和调试它会更容易。这也将允许您向您的用户提供更多有针对性的错误消息(不仅仅是Invalid Password),这应该会改善用户体验。

据我所知,您对正则表达式非常流利,所以我认为给您正则表达式来做您需要的事情是徒劳的。

看到你的评论,我会这样做:

  • 必须是八个字符长:您不需要正则表达式。使用.Length 属性就足够了。

  • 包括一个大写字母:您可以使用[A-Z]+ 正则表达式。如果字符串包含至少一个大写字母,则此正则表达式将产生true

  • 一个特殊字符:您可以使用\W,它将匹配任何不是字母或数字的字符,或者您可以使用类似[!@#] 的东西来指定特殊的自定义列表人物。请注意,$^() 等字符在正则表达式语言中是特殊字符,因此需要像这样对它们进行转义:\$。所以简而言之,你可以使用\W

  • 字母数字字符:使用\w+ 应匹配任何字母和数字以及下划线。

查看this 教程了解更多信息。

【讨论】:

  • 这不是我自己写的,我是从谷歌亲爱的朋友那里得到的
  • @RaniaUmair:我认为您的评论证明了我的观点。我建议您按照我指定的方式对其进行分解。
  • +1 正则表达式很强大,但并不是为了解决宇宙中的任何问题
  • 回复太晚了;但是这种方法也可以准确地告诉用户他们出错的地方。包含所有内容的正则表达式只能说出要求是什么。将其分解为多个“如果”将让您告诉用户:“哦,等等,您至少需要一个符号”等等……对用户更友好。
  • 在这里检查[A-Z](没有+)还不够吗?由于您只是检查密码中是否存在至少一个,因此您只需要匹配一个(而不是连续的多个)。
【解决方案2】:

如果您只需要一个大写字母和特殊字符,那么这应该可以:

@"^(?=.{8,}$)(?=[^A-Z]*[A-Z][^A-Z]*$)\w*\W\w*$"

【讨论】:

  • 字符串AAaaaaaaa#根据这个表达式是不行的
  • 嗯,它是 10 个字符,而不是 8 个字符长并且包含多个大写字母,所以它应该会失败...
  • 你是对的,它确实在问题中这么说。我认为这些规则更像是“至少一个大写”,而不是“正好一个大写”。我不确定这是否是 OP 想要的。
【解决方案3】:
(                   # Start of group
    (?=.*\d)        #   must contain at least one digit
    (?=.*[A-Z])     #   must contain at least one uppercase character
    (?=.*\W)        #   must contain at least one special symbol
       .            #     match anything with previous condition checking
         {8,8}      #        length is exactly 8 characters
)                   # End of group

一行:

((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})

编辑 2019-05-28:

您需要匹配整个输入字符串。因此,您可以将正则表达式括在 ^$ 之间,以防止意外地将部分匹配假设为匹配整个输入:

^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$

来源:

【讨论】:

  • 因为它由12个字符组成
  • 还有一个条件不应该以数字开头我该怎么做?
  • 您可以使用 {8} 缩短它以匹配 8 个字符
  • 匹配 $1eerrrrrrr.. 它没有大写字母。
  • @ShilpiJaiswal 您正在使用标志进行不区分大小写的匹配,或者进行“查找”而不是“匹配”。为确保匹配整个输入字符串,您可以将正则表达式括在 ^$ 之间。试试这个:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
【解决方案4】:

作为一个示例,如何使用可读/可维护的正则表达式来完成。

对于更长的正则表达式,您应该始终使用 RegexOptions.IgnorePatternWhitespace 以允许表达式中的空格和 cmets 以获得更好的可读性。

String[] passwords = { "foobar", "Foobar", "Foobar1", "Fooobar12" };

foreach (String s in passwords) {

    Match password = Regex.Match(s, @"
                                      ^              # Match the start of the string
                                       (?=.*\p{Lu})  # Positive lookahead assertion, is true when there is an uppercase letter
                                       (?=.*\P{L})   # Positive lookahead assertion, is true when there is a non-letter
                                       \S{8,}        # At least 8 non whitespace characters
                                      $              # Match the end of the string
                                     ", RegexOptions.IgnorePatternWhitespace);

    if (password.Success) {
        Console.WriteLine(s + ": valid");
    }
    else {
        Console.WriteLine(s + ": invalid");
    }
}

Console.ReadLine();

【讨论】:

  • 这是滥用lookahead assertion 的最佳方式,将其作为一种“与”模式来覆盖单个正则表达式中的整个约束。适用于更多约束,如果应通过配置启用/禁用某些约束,则可以轻松生成。
  • 使用Unicode categories 是个好主意。世界比 ASCII 更广阔!
【解决方案5】:
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/

【讨论】:

  • 我建议您编辑您的问题并包含一些解释。仅代码答案有时就足够了,但代码+解释答案总是更好
【解决方案6】:

答案是不使用正则表达式。这是集合和计数。

正则表达式是关于顺序的。

在你作为程序员的生活中,你会被要求做很多没有意义的事情。学会更深层次地挖掘。了解问题何时出错。

问题(如果提到正则表达式)是错误的。

伪代码(最近在太多语言之间切换):

if s.length < 8:
    return False
nUpper = nLower = nAlphanum = nSpecial = 0
for c in s:
    if isUpper(c):
        nUpper++
    if isLower(c):
        nLower++
    if isAlphanumeric(c):
        nAlphanum++
    if isSpecial(c):
        nSpecial++
return (0 < nUpper) and (0 < nAlphanum) and (0 < nSpecial)

打赌您几乎立即阅读并理解了上述代码。打赌您使用正则表达式的时间要长得多,并且不太确定它是否正确。扩展正则表达式是有风险的。扩展了上面的内容,更不用说。

请注意,这个问题的措辞不准确。字符集是 ASCII 还是 Unicode,还是 ??我从阅读这个问题的猜测是至少假设一个小写字符。所以我认为假设的最后一条规则应该是:

return (0 < nUpper) and (0 < nLower) and (0 < nAlphanum) and (0 < nSpecial)

(改变帽子以安全为中心,这是一个真的烦人/无用的规则。)

学会知道问题何时出错比聪明的答案重要得多。对错误问题的聪明回答几乎总是错误的。

【讨论】:

  • 我同意。与你一起工作的人越多,需要可读的代码就越多,尽管我看到的一些正则表达式实现作为答案很清楚
  • 我喜欢像你这样的一些用户有勇气说正则表达式并不总是更好的应用解决方案,而且有时,简单的编程更具可读性。
【解决方案7】:

这个问题开始流行起来,出现了很多有趣的建议。

是的,手写很难。所以更简单的解决方案是使用模板。尽管生成的正则表达式可能不是最佳的,但它会更容易维护和/或更改,并且用户将对结果有更好的控制。我可能遗漏了什么,所以任何建设性的批评都会有所帮助。

此链接可能很有趣:match at least 2 digits 2 letters in any order in a stringRegular Expression LanguageCapturing groups

我正在使用这个模板(?=(?:.*?({type})){({count})}),基于我在 SO 中看到的所有正则表达式。下一步是替换所需的模式(numberspecial character ...)并添加长度配置。

我为编写正则表达式 PasswordRegexGenerator.cs 做了一个小课 一个例子:

string result = new PasswordRegexGenerator ( )
        .UpperCase ( 3, -1 )    // ... {3,}
        .Number ( 2, 4 )        // ... {2,4}
        .SpecialCharacter ( 2 ) // ... {2}
        .Total ( 8,-1 )
        .Compose ( );

/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
    private string _elementTemplate = "(?=(?:.*?({type})){({count})})";

    private Dictionary<string, string> _elements = new Dictionary<string, string> {
        { "uppercase", "[A-Z]" },
        { "lowercase", "[a-z]" },
        { "number", @"\d" },
        { "special", @"\W" },
        { "alphanumeric", @"\w" }
    };

    private StringBuilder _sb = new StringBuilder ( );

    private string Construct ( string what, int min, int max )
    {
        StringBuilder sb = new StringBuilder ( _elementTemplate );
        string count = min.ToString ( );

        if ( max == -1 )
        {
            count += ",";
        }
        else if ( max > 0 )
        {
            count += "," + max.ToString();
        }

        return sb
            .Replace ( "({type})", what )
            .Replace ( "({count})", count )
            .ToString ( );
    }

    /// <summary>
    /// Change the template for the generation of the regex parts
    /// </summary>
    /// <param name="newTemplate">the new template</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
    {
        _elementTemplate = newTemplate;
        return this;
       }

    /// <summary>
    /// Change or update the regex for a certain type ( number, uppercase ... )
    /// </summary>
    /// <param name="name">type of the regex</param>
    /// <param name="regex">new value for the regex</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
    {
        if ( _elements.ContainsKey ( name ) )
        {
            _elements[ name ] = regex;
        }
        else
        {
            _elements.Add ( name, regex );
        }
        return this;
    }

    #region construction methods 

    /// <summary>
    /// Adding number requirement
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "number" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "special" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator Total ( int min, int max = 0 )
    {
        string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
        _sb.Append ( ".{" + count + "}" );
        return this;
    }

    #endregion

    public string Compose ()
    {
        return "(" + _sb.ToString ( ) + ")";
    }
}

【讨论】:

    【解决方案8】:

    这么多答案....都不好!

    正则表达式没有 AND 运算符,因此很难编写匹配有效密码的正则表达式,当有效性由某事 AND 某事和某事定义时...

    但是,正则表达式 do 有一个 OR 运算符,所以只需应用 DeMorgan 定理,并编写一个匹配 invalid 密码的正则表达式。

    任何少于 8 个字符的内容 OR 任何不带数字的内容 OR 任何不带大写字母的内容 OR 任何不带特殊字符的内容

    所以:

    ^(.{0,7}|[^0-9]*|[^A-Z]*|[a-zA-Z0-9]*)$
    

    如果有任何匹配项,那么它就是一个无效密码。

    【讨论】:

    • 如果 OP 想要正好 8 个字符,那么您需要添加 |.{9,}。为这个概念 +1
    • 这个问题的伟大而简单的解决方案,虽然我同意单个正则表达式不是实际问题的最佳解决方案。
    • 正则表达式 do 有 AND 运算符,它们被称为前瞻/后瞻断言。
    【解决方案9】:

    您要查找的正则表达式是:/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&amp;\*\[\]"\';:_\-&lt;&gt;\., =\+\/\\]).{8,}$/u

    示例和测试:http://regexr.com/3fhr4

    【讨论】:

    • 允许有空格
    • @sniels 只需将{8,} 之前的. 更改为[^\s]
    【解决方案10】:

    您可以使用以下类进行验证:

    public class PasswordValidator{
    
      private Pattern pattern;
      private Matcher matcher;
    
      private static final String PASSWORD_PATTERN =
              "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";
    
      public PasswordValidator(){
          pattern = Pattern.compile(PASSWORD_PATTERN);
      }
    
      /**
       * Validate password with regular expression
       * @param password password for validation
       * @return true valid password, false invalid password
       */
      public boolean validate(final String password){
    
          matcher = pattern.matcher(password);
          return matcher.matches();
    
      }
    }
    

    其中 6 和 20 是密码的最小和最大长度。

    【讨论】:

      【解决方案11】:
      • 使用非回溯表达式首先匹配整个密码,如果它至少有 8 个字符(这样就不会出现组合爆炸过长但无效的密码):(?&gt;{8,})
      • 使用后向断言来检查是否存在所有必需的字符(AND 条件)。 (?&lt;=...)
      • 至少一个大写字符:(?&lt;=\p{Lu}.*)
      • 至少一个特殊字符(有点模棱两可,但让我们使用非单词):(?&lt;=\W.*)
      • 至少一个字母数字字符(:(?&lt;=\w.*)

      总结:

      (?&gt;.{8,})(?&lt;=\p{Lu}.*)(?&lt;=\W.*)(?&lt;=\w.*)

      【讨论】:

        【解决方案12】:

        最好不要对所有事情都使用正则表达式。这些要求很轻。在 CPU 方面检查标准/验证的字符串操作比正则表达式更便宜和更快!

        【讨论】:

          【解决方案13】:

          var regex =/^(?=.*\d)(?=.*[!@#$%^&*])(?=.*[a-z])(?=.*[A-Z]).{8,64}$/;
          
           
          function test() {
          
           if(regex.test(document.getElementById("txtPassword").value)===false)
           {
           alert("Min 6,Max 64,At Least One Uppercase Character,One Lowercase Character,One Numeric Value And One Special Character(!@#$%^&*) Required ");
           }
           else
           {
           alert("Success");
           }
          }
          <input type="text" id="txtPassword" />
          <button id="testBtn" onclick=test()>CheckPassword</button>

          【讨论】:

          • 虽然这段代码 sn-p 可以解决问题,但它没有解释为什么或如何回答这个问题。请include an explanation for your code,因为这确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。您可以使用edit 按钮改进此答案以获得更多选票和声誉!
          【解决方案14】:

          我找到的至少包含 8 个字符的字符,由至少 1 个小写字母和 1 个大写字母以及 1 个数字和 1 个符号组成。

          ^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,})$
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-05-26
            • 1970-01-01
            • 2015-01-18
            • 2015-03-12
            • 1970-01-01
            相关资源
            最近更新 更多