检查密码是否为“ 8个字符,包括1个大写字母,1个特殊字符,字母数字字符”的正则表达式


102

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

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

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

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

如何为必须包含八个大写字母(一个大写字母,一个特殊字符和字母数字字符)的密码编写密码?


26
为什么需要一个正则表达式呢?符合您要求的完整正则表达式将非常长且复杂。用C#代码编写约束更加容易。
Greg Hewgill

32
您是否考虑过检查强密码,而不是检查密码是否符合某些任意规则,这些规则并不完美地代表了强密码?有很多库和程序,当输入密码时,它们将决定其强度。
韦恩·康拉德

4
@GregHewgill如果可以的话,我会反对你的评论:-)这看起来像是另一种情况:“如果你只有一把锤子,一切都会开始像钉子一样”。
Christian.K

3
你需要的正是一个大写/特殊字符或至少一个?
mmdemirbas 2012年

4
根据用户的要求,您是说您的用户在规定实施细节吗?也许他们应该自己编写代码。老实说,我认为如果您只是创建计数器并逐个检查每个字符,并为与规则匹配的每个字符增加相应的计数器,则更容易维护和理解。从技术的角度来看,这并不能给任何人留下深刻的印象,但是为什么使事情变得容易出错且难以更新呢?

Answers:


132

您所追求的正则表达式很可能非常庞大且难以维持,尤其是对于不那么熟悉正则表达式的人。

我认为分解您的正则表达式并一次执行一次会更容易。可能还需要做更多的工作,但是我敢肯定,维护和调试它会更容易。这还将使您能够向用户(不仅仅是Invalid Password)提供更多定向错误消息,这将改善用户体验。

从我所看到的来看,您在regex方面相当流利,因此我认为为您提供正则表达式来做您需要的事情是徒劳的。

看到您的评论,这就是我的处理方式:

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

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

  • 一个特殊字符:可以使用\W匹配任何非字母或数字的字符,也可以使用诸如此类的东西[!@#]指定特殊字符的自定义列表。不过,请注意字符如$^()是在正则表达式语言的特殊字符,所以需要进行转义像这样:\$。简而言之,您可以使用\W

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

查看教程以获取更多信息。


2
我还没有写我自己的照片,我是从Google亲爱的朋友那里得到的
Rania Umair 2012年

4
@RaniaUmair:我认为您的评论证明了我的观点。我建议您像我指定的那样分解它。
npinti 2012年

35
+1正则表达式功能强大,但无意解决宇宙中的任何问题
Cristian Lupascu 2012年

@ w0lf:我完全同意。正则表达式功能强大,但是它变得太复杂,太快,因此最好使其保持简单。
npinti 2012年

您能帮我吗,我需要一个接受至少一个数字且最多三个其他
字符

107
(                   # 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:

您需要匹配整个输入字符串。因此,您可以将regex放在^和之间,$以防止意外地将部分匹配假定为匹配整个输入:

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

资料来源:


58
因为它包含12个字符
mmdemirbas

还有一个条件不应该以数字开头怎么办?
Lijo 2014年

7
您可以使用{8}来缩短它的长度,以匹配8个字符
Angelo Tricarico

匹配$ 1eerrrrrrr..。没有大写字母。
Shilpi Jaiswal,

@ShilpiJaiswal您正在使用一个不区分大小写的匹配标志,或者进行“查找”而不是“匹配”。为确保匹配整个输入字符串,可以在^和之间加上正则表达式$。试试这个:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas '19

35

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

正则表达式没有AND运算符,因此,当有效性是由AND和其他事物以及其他事物定义的时,很难编写与有效密码匹配的正则表达式。

但是,正则表达式确实具有OR运算符,因此只需应用DeMorgan定理,并编写与无效密码匹配的正则表达式即可。

少于8个字符什么什么没有编号没有大写什么不带特殊字符什么

所以:

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

如果符合条件,则为无效密码。


3
如果OP恰好需要8个字符,那么您需要添加|.{9,}。+1的概念
Daniel

尽管我同意单个正则表达式并不是针对实际问题的最佳选择,但该问题的解决方案简单而有效。
Siderite Zackwehdex

1
正则表达式确实具有AND运算符,它们称为先行/后备断言。
相对

13

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

正则表达式与顺序有关。

在作为程序员的生活中,您会被要求做很多没有意义的事情。学习更深入地学习。了解问题出在什么时候。

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

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

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)

(将帽子更改为以安全为中心,这是一个非常烦人/没有用的规则。)

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


2
我同意。与您合作的人越多,尽管我看到的一些正则表达式实现非常清楚,但仍需要更多的代码可读性
Nicola Peluchetti 2015年

我喜欢像您这样的一些用户,勇于说Regex并非总是适用的更好解决方案,而且有时候,简单的编程更具可读性。
schlebe

12

例如,如何使用可读/可维护的正则表达式来完成此操作。

对于更长的正则表达式,应始终使用表达式中的RegexOptions.IgnorePatternWhitespace空格和注释以提高可读性。

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“和”模式来覆盖单个正则表达式中整个约束的最佳方法。适用于更多约束,如果某些约束应通过配置启用/禁用,则可以轻松生成。
dognose

2
Unicode类别的使用是一个好主意。世界比ASCII还宽!
Walter Tross 2015年

1

如果只需要一个大写字母和特殊字符,则应该可以使用:

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

AAaaaaaaa#根据此表达式,字符串不正确
Cristian Lupascu 2012年

3
好吧,它是10个字符,而不是8个字符长,并且包含多个大写字母,所以它应该失败...
user1096188 2012年

4
您是对的,它确实在问题中这样说。我认为这些规则更像是“至少一个大写字母”,而不是“完全一个大写字母”。我不确定这是否是OP想要的。
克里斯蒂安·卢帕斯库


0

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

是的,用手写很难。因此,更简单的解决方案是使用模板。尽管生成的正则表达式可能不是最佳的,但它更易于维护和/或更改,并且用户可以更好地控制结果。我可能错过了一些东西,因此任何建设性的批评都会有所帮助。

该链接可能很有趣:字符串中以任意顺序匹配至少2位2个字母正则表达式语言捕获组

我正在(?=(?:.*?({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 ( ) + ")";
    }
}

0

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

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是密码的最小和最大长度。


0
  • 如果它至少包含8个字符,则使用非回溯表达式首先匹配整个密码(这样,很长一段时间都不会出现组合爆炸,但是无效的密码): (?>{8,})
  • 使用后向断言来检查是否存在所有必需的字符(AND条件)。 (?<=...)
  • 至少一个大写字符: (?<=\p{Lu}.*)
  • 至少一个特殊字符(有点模棱两可,但让我们使用非单词): (?<=\W.*)
  • 至少一个字母数字字符(: (?<=\w.*)

总结:

(?>.{8,})(?<=\p{Lu}.*)(?<=\W.*)(?<=\w.*)


0

最好不要对所有内容都使用正则表达式。这些要求很轻。在CPU上,用于检查条件/验证的字符串操作比正则表达式便宜得多,而且速度更快!


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.