Biểu thức chính quy để kiểm tra xem mật khẩu có phải là "8 ký tự bao gồm 1 ký tự hoa, 1 ký tự đặc biệt, ký tự chữ và số"


102

Tôi muốn một biểu thức chính quy để kiểm tra điều đó

mật khẩu phải có tám ký tự bao gồm một ký tự viết hoa, một ký tự đặc biệt và các ký tự chữ và số.

Và đây là biểu thức xác thực của tôi dành cho tám ký tự bao gồm một ký tự hoa, một ký tự viết thường và một số hoặc ký tự đặc biệt.

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

Làm cách nào tôi có thể viết nó cho mật khẩu phải có tám ký tự bao gồm một ký tự hoa, một ký tự đặc biệt và các ký tự chữ và số?


26
Tại sao bạn cần một biểu thức chính quy cho điều này? Một biểu thức chính quy hoàn chỉnh phù hợp với yêu cầu của bạn sẽ rất dài và phức tạp. Viết các ràng buộc của bạn trong mã C # sẽ dễ dàng hơn.
Greg Hewgill

32
Bạn đã từng cân nhắc việc kiểm tra một mật khẩu mạnh, thay vì kiểm tra xem mật khẩu có đáp ứng một số quy tắc tùy ý là một proxy không hoàn hảo cho một mật khẩu mạnh? Có rất nhiều thư viện và chương trình, khi được cấp mật khẩu, nó sẽ xác định độ mạnh của nó.
Wayne Conrad

4
@GregHewgill Tôi sẽ ủng hộ nhận xét của bạn nếu tôi có thể :-) Điều này giống như một trường hợp khác của "nếu tất cả những gì bạn có là một cái búa, mọi thứ bắt đầu giống như một cái đinh".
Christian.K

3
Bạn có cần chính xác một chữ hoa / ký tự đặc biệt hay ít nhất một ký tự ?
mmdemirbas

4
Theo yêu cầu của người dùng, bạn có nghĩa là người dùng của bạn đang ra lệnh chi tiết triển khai? Có lẽ họ chỉ nên tự viết mã này. Thành thật mà nói, tôi nghĩ sẽ dễ dàng duy trì và dễ hiểu hơn nếu bạn chỉ tạo bộ đếm và kiểm tra từng ký tự một, tăng bộ đếm thích hợp cho mọi ký tự khớp với một quy tắc. Từ quan điểm kỹ thuật, nó không phải là thứ gây ấn tượng với bất kỳ ai, nhưng tại sao lại phức tạp hóa mọi thứ với một thứ dễ xảy ra lỗi và khó cập nhật?

Câu trả lời:


132

Biểu thức chính quy mà bạn đang theo dõi rất có thể sẽ rất lớn và là một cơn ác mộng để duy trì, đặc biệt là đối với những người không quen thuộc với biểu thức chính quy.

Tôi nghĩ sẽ dễ dàng hơn để chia nhỏ regex của bạn và làm từng chút một. Có thể mất nhiều thời gian hơn để làm, nhưng tôi khá chắc chắn rằng việc duy trì nó và gỡ lỗi nó sẽ dễ dàng hơn. Điều này cũng sẽ cho phép bạn cung cấp nhiều thông báo lỗi trực tiếp hơn cho người dùng của bạn (ngoài chỉ Invalid Password), điều này sẽ cải thiện trải nghiệm người dùng.

Từ những gì tôi thấy bạn khá thông thạo regex, vì vậy tôi cho rằng việc cung cấp cho bạn các biểu thức chính quy để thực hiện những gì bạn cần sẽ là vô ích.

Xem bình luận của bạn, đây là cách tôi sẽ làm về nó:

  • Phải có tám ký tự Dài: Bạn không cần regex cho điều này. Sử dụng .Lengthtài sản phải là đủ.

  • Bao gồm một chữ cái viết hoa: Bạn có thể sử dụng [A-Z]+biểu thức chính quy. Nếu chuỗi chứa ít nhất một chữ cái viết hoa, thì biểu thức chính quy này sẽ mang lại kết quả true.

  • Một ký tự đặc biệt: Bạn có thể sử dụng \Wký tự sẽ khớp với bất kỳ ký tự nào không phải là chữ cái hoặc số hoặc nếu không, bạn có thể sử dụng một cái gì đó tương tự như vậy [!@#]để chỉ định danh sách tùy chỉnh các ký tự đặc biệt. Lưu ý rằng mặc dù các nhân vật chẳng hạn như $, ^, ()là nhân vật đặc biệt trong ngôn ngữ biểu hiện thường xuyên, vì vậy họ cần phải được thoát như vậy: \$. Vì vậy, trong ngắn hạn, bạn có thể sử dụng \W.

  • Ký tự chữ và số: Sử dụng ký tự \w+phải khớp với bất kỳ chữ cái và số nào và gạch dưới.

Hãy xem hướng dẫn này để biết thêm thông tin.


2
Tôi đã không viết điều này cho bản thân tôi, tôi lấy nó từ người bạn thân yêu của google
Rania Umair

4
@RaniaUmair: Tôi nghĩ rằng nhận xét của bạn chứng minh quan điểm của tôi. Tôi khuyên bạn nên chia nhỏ nó như tôi đã chỉ định.
npinti

35
1 Regex là mạnh mẽ, nhưng không có nghĩa là để giải quyết bất kỳ vấn đề trong vũ trụ
Cristian Lupascu

@ w0lf: Tôi không thể đồng ý hơn. Regex rất mạnh, tuy nhiên, nó quá phức tạp quá nhanh, vì vậy tốt hơn hết hãy giữ nó đơn giản.
npinti

bạn có thể giúp tôi tôi cần một regx mà chấp nhận ít nhất một số lượng và tối đa 3 charecters khác có thể là bất cứ điều gì
Lijo

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

Trong một dòng:

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

Chỉnh sửa 2019-05-28:

Bạn cần phải khớp toàn bộ chuỗi đầu vào. Vì vậy, bạn có thể bao gồm regex giữa ^$để tránh việc vô tình giả định các kết quả phù hợp từng phần là khớp với toàn bộ đầu vào:

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

Nguồn:


58
Bởi vì nó bao gồm 12 ký tự
mmdemirbas

một điều kiện nữa không được bắt đầu bằng một chữ số làm thế nào tôi có thể làm điều này?
Lijo

7
Bạn có thể rút ngắn nó sử dụng {8} thay vì để phù hợp với 8 ký tự
Angelo Tricarico

đối sánh của nó với $ 1eerrrrrrr .. nó không có chữ hoa.
Shilpi Jaiswal

@ShilpiJaiswal Bạn đang sử dụng cờ cho đối sánh không phân biệt chữ hoa chữ thường hoặc thực hiện "tìm" thay vì "khớp". Để đảm bảo rằng bạn đang khớp với toàn bộ chuỗi đầu vào, bạn có thể bao gồm regex giữa ^$. Hãy thử điều này:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Rất nhiều câu trả lời .... tất cả đều tệ!

Biểu thức chính quy không có toán tử AND, vì vậy, khá khó để viết một regex khớp với mật khẩu hợp lệ, khi tính hợp lệ được xác định bởi thứ gì đó VÀ thứ khác VÀ thứ khác ...

Nhưng, biểu thức thông thường làm có một toán tử OR, vì vậy chỉ cần áp dụng định lý DeMorgan, và viết một regex phù hợp với không hợp lệ mật khẩu.

bất kỳ thứ gì có ít hơn 8 ký tự HOẶC bất kỳ thứ gì không có số HOẶC bất kỳ thứ gì không có chữ hoa HOẶC bất kỳ thứ gì không có ký tự đặc biệt

Vì thế:

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

Nếu bất kỳ điều gì khớp với điều đó, thì đó là mật khẩu không hợp lệ .


3
Nếu OP muốn chính xác 8 ký tự, vì vậy bạn cần phải thêm |.{9,}. +1 cho khái niệm
Daniel

Giải pháp tuyệt vời và đơn giản cho câu hỏi, mặc dù tôi đồng ý rằng một biểu thức chính quy không phải là giải pháp tối ưu cho vấn đề thực tế.
Siderite Zackwehdex

1
Biểu thức thông thường làm có VÀ khai thác, chúng được gọi lookahead / lookbehind khẳng định.
relatively_random

13

Câu trả lời là không sử dụng biểu thức chính quy. Đây là tập hợp và đếm.

Biểu thức chính quy là về thứ tự.

Trong cuộc sống của bạn với tư cách là một lập trình viên, bạn sẽ phải làm nhiều việc không có ý nghĩa. Tìm hiểu để đào sâu hơn một cấp độ. Tìm hiểu khi câu hỏi sai.

Câu hỏi (nếu nó đề cập đến biểu thức chính quy) là sai.

Mã giả (đã chuyển đổi giữa quá nhiều ngôn ngữ, muộn):

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)

Cá là bạn đã đọc và hiểu đoạn mã trên gần như ngay lập tức. Đặt cược là bạn mất nhiều thời gian hơn với regex, và ít chắc chắn rằng nó là chính xác. Mở rộng regex là rủi ro. Mở rộng ngay bên trên, ít hơn nhiều.

Cũng lưu ý rằng câu hỏi được diễn đạt không chính xác. Bộ ký tự là ASCII hay Unicode, hoặc ?? Suy đoán của tôi khi đọc câu hỏi là ít nhất một ký tự viết thường được giả định. Vì vậy, tôi nghĩ quy tắc cuối cùng được giả định nên là:

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

(Thay đổi mũ thành tập trung vào bảo mật, đây là một quy tắc thực sự khó chịu / không hữu ích.)

Học cách biết khi nào câu hỏi sai quan trọng hơn những câu trả lời thông minh. Một câu trả lời thông minh cho câu hỏi sai hầu như luôn luôn sai.


2
Tôi đồng ý. Càng nhiều người bạn làm việc với, mã hơn nhu cầu để có thể đọc mặc dù một số regexp thực hiện tôi thấy như câu trả lời là khá rõ ràng
Nicola Peluchetti

Tôi thích rằng một số người dùng như bạn có can đảm để nói rằng Regex không phải lúc nào cũng là giải pháp tốt hơn để áp dụng và đôi khi, lập trình đơn giản sẽ dễ đọc hơn.
schlebe

12

Ví dụ về cách điều này có thể được thực hiện với một regex có thể đọc được / có thể bảo trì.

Đối với regex dài hơn, bạn nên luôn sử dụng RegexOptions.IgnorePatternWhitespaceđể cho phép khoảng trắng và chú thích trong biểu thức để dễ đọc hơn.

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();

Đây là cách tốt nhất để lạm dụng kiểu lookahead assertionnhư một mẫu "và" để che toàn bộ ràng buộc trong một regex duy nhất. Hoạt động với nhiều ràng buộc hơn và có thể dễ dàng tạo ra nếu một số ràng buộc nên được bật / tắt bằng cấu hình.
dognose

2
Việc sử dụng các danh mục Unicode là một ý tưởng tuyệt vời. Thế giới rộng lớn hơn ASCII!
Walter Tross

1

Nếu bạn chỉ cần một chữ hoa và ký tự đặc biệt thì điều này sẽ hoạt động:

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

Chuỗi AAaaaaaaa#không ổn theo biểu thức này
Cristian Lupascu

3
Vâng, đó là 10 thay vì 8 ký tự và có chứa nhiều hơn một chữ hoa sau, vì vậy nó nên thất bại ...
user1096188

4
Bạn đúng, nó không nói điều này trong câu hỏi. Tôi nghĩ những quy tắc này giống như "ít nhất một chữ hoa" thay vì "chính xác một chữ hoa" . Tôi không chắc đó là những gì OP muốn.
Cristian Lupascu

1

Biểu thức chính quy bạn đang tìm kiếm là: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*\[\]"\';:_\-<>\., =\+\/\\]).{8,}$/u .

Ví dụ và thử nghiệm: http://regexr.com/3fhr4


Không gian được phép
Swimburger

1
@sniels Chỉ cần thay đổi .trước {8,}thành [^\s].
Lucas Silva

0

Câu hỏi này bắt đầu lan truyền và rất nhiều gợi ý thú vị xuất hiện.

Vâng, viết bằng tay rất khó. Vì vậy, một giải pháp dễ dàng hơn là sử dụng một mẫu. Mặc dù kết quả regex có thể không phải là tối ưu nhất, nó sẽ dễ bảo trì và / hoặc thay đổi hơn và người dùng sẽ kiểm soát tốt hơn kết quả. Có thể là tôi đã bỏ lỡ điều gì đó, vì vậy bất kỳ lời phê bình mang tính xây dựng nào cũng sẽ hữu ích.

Các liên kết này có thể thú vị: so khớp ít nhất 2 chữ số 2 chữ cái theo thứ tự bất kỳ trong một chuỗi , Ngôn ngữ biểu thức chính quy , Nhóm nắm bắt

Tôi đang sử dụng mẫu này (?=(?:.*?({type})){({count})})dựa trên tất cả regex mà tôi đã thấy trong SO. Bước tiếp theo là thay thế mẫu cần thiết ( number,special character ...) và thêm cấu hình cho độ dài.

Tôi đã tạo một lớp học nhỏ để soạn thảo regex PasswordRegexGenerator.cs Một ví dụ:

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

Bạn có thể sử dụng lớp dưới đây để xác thực:

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();

  }
}

trong đó 6 và 20 là độ dài tối thiểu và tối đa cho mật khẩu.


0
  • Sử dụng biểu thức không theo dõi để khớp với toàn bộ mật khẩu trước, nếu mật khẩu đó có ít nhất 8 ký tự (theo cách này, không có sự bùng nổ tổ hợp đối với mật khẩu dài nhưng không hợp lệ): (?>{8,})
  • Sử dụng xác nhận phía sau để kiểm tra sự hiện diện của tất cả các ký tự bắt buộc (điều kiện AND). (?<=...)
  • Ít nhất một ký tự viết hoa: (?<=\p{Lu}.*)
  • Ít nhất một ký tự đặc biệt (hơi mơ hồ, nhưng hãy sử dụng không phải từ): (?<=\W.*)
  • Ít nhất một ký tự chữ và số (: (?<=\w.*)

Tóm tắt:

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


0

Tốt nhất là không sử dụng regex cho mọi thứ. Những yêu cầu đó rất nhẹ. Trên các hoạt động chuỗi khôn ngoan của CPU để kiểm tra các tiêu chí / xác nhận là rẻ hơn và nhanh hơn nhiều so với regex!


-2
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/

15
Tôi khuyên bạn nên chỉnh sửa câu hỏi của mình và kèm theo một số giải thích. Mã chỉ câu trả lời là đủ đôi khi tốt, nhưng mã + giải thích câu trả lời là luôn luôn tốt hơn
Barranka
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.