Ekspresi reguler untuk memeriksa apakah kata sandi adalah "8 karakter termasuk 1 huruf besar, 1 karakter khusus, karakter alfanumerik"


102

Saya ingin ekspresi reguler memeriksanya

kata sandi harus terdiri dari delapan karakter termasuk satu huruf besar, satu karakter khusus dan karakter alfanumerik.

Dan inilah ekspresi validasi saya yang terdiri dari delapan karakter termasuk satu huruf besar, satu huruf kecil, dan satu angka atau karakter khusus.

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

Bagaimana saya bisa menulisnya untuk kata sandi yang harus terdiri dari delapan karakter termasuk satu huruf besar, satu karakter khusus dan karakter alfanumerik?


26
Mengapa Anda membutuhkan ekspresi reguler untuk ini? Ekspresi reguler lengkap yang cocok dengan kebutuhan Anda akan sangat panjang dan rumit. Lebih mudah untuk menulis batasan Anda dalam kode C #.
Greg Hewgill

32
Pernahkah Anda mempertimbangkan untuk memeriksa kata sandi yang kuat, daripada memeriksa bahwa kata sandi memenuhi beberapa aturan sewenang-wenang yang merupakan proxy yang tidak sempurna untuk kata sandi yang kuat? Ada banyak pustaka dan program yang, jika diberi kata sandi, akan menentukan kekuatannya.
Wayne Conrad

4
@GregHewgill Saya akan memberi suara positif pada komentar Anda jika saya bisa :-) Ini terlihat seperti kasus lain dari "jika yang Anda miliki hanyalah palu, semuanya mulai terlihat seperti paku".
Christian.K

3
Apakah Anda memerlukan tepat satu huruf besar / karakter khusus atau setidaknya satu?
mmdemirbas

4
Menurut kebutuhan pengguna, apakah yang Anda maksud pengguna Anda mendiktekan detail implementasi? Mungkin mereka harus membuat kode sendiri, lalu. Sejujurnya, menurut saya akan lebih mudah untuk mempertahankan dan memahami jika Anda baru saja membuat penghitung dan memeriksa setiap karakter satu per satu, menambah penghitung yang sesuai untuk setiap karakter yang cocok dengan aturan. Dari sudut pandang teknis, ini bukan sesuatu yang akan mengesankan siapa pun, tetapi mengapa mempersulit hal-hal dengan sesuatu yang rawan kesalahan dan sulit diperbarui?

Jawaban:


132

Ekspresi reguler yang Anda cari kemungkinan besar akan menjadi besar dan mimpi buruk untuk dipertahankan terutama bagi orang-orang yang tidak begitu akrab dengan ekspresi reguler.

Saya rasa akan lebih mudah untuk memecah ekspresi reguler Anda dan melakukannya sedikit demi sedikit. Mungkin perlu sedikit lebih banyak untuk dilakukan, tetapi saya cukup yakin bahwa mempertahankan dan men-debugnya akan lebih mudah. Ini juga akan memungkinkan Anda untuk memberikan pesan kesalahan yang lebih terarah kepada pengguna Anda (selain hanya Invalid Password) yang akan meningkatkan pengalaman pengguna.

Dari apa yang saya lihat, Anda cukup fasih menggunakan ekspresi reguler, jadi saya berasumsi bahwa memberi Anda ekspresi reguler untuk melakukan apa yang Anda butuhkan akan sia-sia.

Melihat komentar Anda, inilah yang akan saya lakukan:

  • Harus delapan karakter Panjang: Anda tidak memerlukan ekspresi reguler untuk ini. Menggunakan .Lengthproperti sudah cukup.

  • Menyertakan satu huruf besar: Anda dapat menggunakan [A-Z]+ekspresi reguler. Jika string berisi setidaknya satu huruf besar, ekspresi reguler ini akan menghasilkan true.

  • Satu karakter khusus: Anda dapat menggunakan yang \Wmana akan cocok dengan karakter apa pun yang bukan huruf atau angka atau yang lain, Anda dapat menggunakan sesuatu seperti itu [!@#]untuk menentukan daftar karakter khusus. Catatan bahwa meskipun karakter seperti $, ^, (dan )karakter khusus dalam bahasa ekspresi reguler, sehingga mereka harus melarikan diri seperti: \$. Jadi singkatnya, Anda mungkin menggunakan \W.

  • Karakter alfanumerik: Penggunaan \w+harus cocok dengan huruf dan angka apa pun serta garis bawah.

Lihat tutorial ini untuk informasi lebih lanjut.


2
saya belum menulis ini sendiri, saya mendapatkannya dari teman google tersayang
Rania Umair

4
@ RaniaUmair: Saya pikir komentar Anda membuktikan maksud saya. Saya akan merekomendasikan agar Anda memecahnya seperti yang telah saya tentukan.
npinti

35
+1 Regex sangat kuat, tetapi tidak dimaksudkan untuk menyelesaikan masalah apa pun di alam semesta
Cristian Lupascu

@ w0lf: Saya sangat setuju. Regex sangat kuat, namun terlalu rumit terlalu cepat, jadi lebih baik buat sederhana saja.
npinti

dapatkah Anda membantu saya, saya memerlukan regx yang menerima setidaknya satu nomor dan maksimal 3 karakter lainnya dapat berupa apa saja
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

Dalam satu baris:

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

Sunting 2019-05-28:

Anda harus mencocokkan seluruh string masukan. Jadi, Anda bisa mengapit regex di antara ^dan $untuk mencegah asumsi kecocokan parsial secara tidak sengaja sebagai pencocokan seluruh input:

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

Sumber:


58
Karena terdiri dari 12 karakter
mmdemirbas

satu lagi syarat tidak boleh dimulai dengan digit bagaimana saya bisa melakukan ini?
Lijo

7
Anda dapat mempersingkatnya menggunakan {8} untuk mencocokkan 8 karakter
Angelo Tricarico

pencocokannya untuk $ 1eerrrrrrr .. tidak ada huruf besar.
Shilpi Jaiswal

@ShilpiJaiswal Entah Anda menggunakan bendera untuk pencocokan tidak peka huruf besar / kecil, atau membuat "temukan" alih-alih "cocok". Untuk memastikan Anda mencocokkan seluruh string input, Anda dapat mengapit regex antara ^dan $. Coba ini:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Begitu banyak jawaban .... semuanya buruk!

Ekspresi reguler tidak memiliki operator DAN, jadi cukup sulit untuk menulis regex yang cocok dengan kata sandi yang valid, ketika validitas ditentukan oleh sesuatu DAN sesuatu yang lain DAN sesuatu yang lain ...

Tapi, ekspresi reguler melakukan memiliki OR operator, jadi hanya berlaku teorema DeMorgan, dan menulis regex yang cocok valid password.

apapun dengan kurang dari 8 karakter ATAU apapun tanpa angka ATAU apapun tanpa huruf besar ATAU apapun tanpa karakter khusus

Begitu:

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

Jika ada yang cocok, maka itu adalah kata sandi yang tidak valid .


3
Jika OP menginginkan tepat 8 karakter, maka Anda perlu menambahkan |.{9,}. 1 untuk konsep
Daniel

Solusi hebat dan sederhana untuk pertanyaan tersebut, meskipun saya setuju satu ekspresi reguler bukanlah yang optimal untuk masalah sebenarnya.
Siderite Zackwehdex

1
Ekspresi reguler memang memiliki operator AND, mereka disebut pernyataan lookahead / lookbehind.
relative_random

13

Jawabannya adalah tidak menggunakan ekspresi reguler. Ini adalah set dan penghitungan.

Ekspresi reguler adalah tentang keteraturan.

Dalam kehidupan Anda sebagai programmer, Anda akan diminta untuk melakukan banyak hal yang tidak masuk akal. Belajar untuk menggali lebih dalam. Pelajari saat pertanyaannya salah.

Pertanyaannya (jika disebutkan ekspresi reguler) salah.

Pseudocode (akhir-akhir ini beralih di antara terlalu banyak bahasa):

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)

Taruhan Anda membaca dan memahami kode di atas hampir secara instan. Taruhan Anda membutuhkan waktu lebih lama dengan regex, dan kurang yakin itu benar. Memperpanjang regex berisiko. Perluas segera di atas, apalagi.

Perhatikan juga pertanyaannya diutarakan secara tidak tepat. Apakah set karakter ASCII atau Unicode, atau ?? Dugaan saya dari membaca pertanyaan tersebut adalah bahwa setidaknya satu karakter huruf kecil diasumsikan. Jadi saya pikir aturan terakhir yang diasumsikan harus:

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

(Mengubah topi menjadi berfokus pada keamanan, ini adalah aturan yang sangat mengganggu / tidak berguna.)

Belajar mengetahui kapan pertanyaannya salah secara besar-besaran lebih penting daripada jawaban yang cerdik. Jawaban cerdas atas pertanyaan yang salah hampir selalu salah.


2
Saya setuju. Semakin banyak orang yang bekerja dengan Anda, semakin banyak kode yang perlu dibaca meskipun beberapa implementasi regexp yang saya lihat sebagai jawabannya cukup jelas
Nicola Peluchetti

Saya suka bahwa beberapa pengguna seperti Anda memiliki keberanian untuk mengatakan bahwa Regex tidak selalu merupakan solusi yang lebih baik untuk diterapkan dan terkadang, pemrograman sederhana lebih mudah dibaca.
schlebe

12

Sebagai contoh bagaimana hal ini dapat dilakukan dengan regex yang dapat dibaca / dipelihara.

Untuk regex yang lebih panjang, Anda harus selalu menggunakan RegexOptions.IgnorePatternWhitespacespasi kosong dan komentar dalam ekspresi agar lebih mudah dibaca.

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

Ini adalah cara terbaik untuk menyalahgunakan pola lookahead assertionsebagai "dan" untuk menutupi seluruh batasan dalam satu regex. Berfungsi untuk lebih banyak batasan dan dapat dengan mudah dibuat jika beberapa batasan harus diaktifkan / dinonaktifkan oleh konfigurasi.
kenalkan

2
Penggunaan kategori Unicode adalah ide yang bagus. Dunia lebih luas dari ASCII!
Walter Tross

1

Jika Anda hanya membutuhkan satu huruf besar dan karakter khusus maka ini seharusnya berfungsi:

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

String AAaaaaaaa#tidak OK menurut ungkapan ini
Cristian Lupascu

3
Yah, panjangnya 10, bukan 8 karakter dan berisi lebih dari satu huruf besar, jadi seharusnya gagal ...
user1096188

4
Anda benar, itu tidak mengatakan ini dalam pertanyaan. Saya pikir aturan ini lebih seperti "setidaknya satu huruf besar" daripada "tepat satu huruf besar" . Saya tidak yakin itu yang diinginkan OP.
Cristian Lupascu


0

Pertanyaan ini mulai viral dan banyak saran menarik bermunculan.

Ya, menulis dengan tangan itu sulit. Jadi solusi yang lebih mudah adalah dengan menggunakan template. Meskipun regex yang dihasilkan mungkin tidak optimal, akan lebih mudah untuk mempertahankan dan / atau mengubah, dan pengguna akan memiliki kontrol yang lebih baik atas hasilnya. Ada kemungkinan saya melewatkan sesuatu, jadi kritik yang membangun akan membantu.

Tautan ini mungkin menarik: cocokkan setidaknya 2 digit 2 huruf dalam urutan apa pun dalam string , Bahasa Ekspresi Reguler , Grup penangkap

Saya menggunakan template ini (?=(?:.*?({type})){({count})})berdasarkan semua regex yang saya lihat di SO. Langkah selanjutnya adalah mengganti pola yang dibutuhkan ( number, special character...) dan menambahkan konfigurasi panjang.

Saya telah membuat kelas kecil untuk membuat regex PasswordRegexGenerator.cs Contoh:

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

Anda dapat menggunakan kelas di bawah ini untuk validasi:

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

  }
}

dimana 6 dan 20 adalah panjang minimum dan maksimum untuk kata sandi.


0
  • Gunakan ekspresi nonmundur untuk mencocokkan seluruh kata sandi terlebih dahulu, jika memiliki setidaknya 8 karakter (dengan cara ini, tidak ada ledakan kombinatorial yang lama, tetapi kata sandi tidak valid): (?>{8,})
  • Gunakan pernyataan lookbehind untuk memeriksa keberadaan semua karakter yang diperlukan (kondisi DAN). (?<=...)
  • Setidaknya satu karakter huruf besar: (?<=\p{Lu}.*)
  • Setidaknya satu karakter khusus (agak ambigu, tapi mari kita gunakan bukan kata): (?<=\W.*)
  • Setidaknya satu karakter alfanumerik (: (?<=\w.*)

Jumlahkan:

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


0

Yang terbaik adalah tidak menggunakan regex untuk semuanya. Persyaratan tersebut sangat ringan. Pada operasi string berdasarkan CPU untuk memeriksa kriteria / validasi jauh lebih murah dan lebih cepat daripada regex!


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

15
Saya sarankan Anda mengedit pertanyaan Anda dan menyertakan beberapa penjelasan. Jawaban hanya kode terkadang cukup baik, tetapi jawaban kode + penjelasan selalu lebih baik
Barranka
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.