Wyrażenie regularne do sprawdzania, czy hasło składa się z „8 znaków, w tym 1 wielka litera, 1 znak specjalny, znaki alfanumeryczne”


102

Potrzebuję wyrażenia regularnego, aby to sprawdzić

hasło musi mieć osiem znaków, w tym jedną wielką literę, jeden znak specjalny i znaki alfanumeryczne.

A oto moje wyrażenie walidacyjne, które obejmuje osiem znaków, w tym jedną wielką literę, jedną małą literę i jedną cyfrę lub znak specjalny.

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

Jak mogę napisać hasło, które musi składać się z ośmiu znaków, w tym jednej wielkiej litery, jednego znaku specjalnego i znaków alfanumerycznych?


26
Dlaczego potrzebujesz do tego wyrażenia regularnego? Pełne wyrażenie regularne spełniające Twoje wymagania będzie bardzo długie i złożone. Łatwiej jest pisać ograniczenia w kodzie C #.
Greg Hewgill

33
Czy zastanawiałeś się nad sprawdzeniem silnego hasła, zamiast sprawdzania, czy spełnia ono jakieś arbitralne zasady, które są niedoskonałym proxy dla silnego hasła? Istnieje wiele bibliotek i programów, które po podaniu hasła określą jego siłę.
Wayne Conrad,

4
@GregHewgill Głosowałbym za Twoim komentarzem, gdybym mógł :-) To wygląda jak kolejny przypadek „jeśli masz tylko młotek, wszystko zaczyna wyglądać jak gwóźdź”.
Christian.K

3
Czy potrzebujesz dokładnie jednej wielkiej litery / znaku specjalnego, czy przynajmniej jednej?
mmdemirbas

4
Czy mówiąc o wymaganiach użytkownika, masz na myśli, że dyktuje on szczegóły implementacji? Być może powinni więc sami to zakodować. Szczerze mówiąc, myślę, że byłoby łatwiej zachować i zrozumieć, gdybyś utworzył liczniki i sprawdzał każdy znak jeden po drugim, zwiększając odpowiednie liczniki dla każdego znaku, który pasuje do reguły. Z technicznego punktu widzenia nie jest to coś, co na nikim zaimponuje, ale po co komplikować sprawę czymś, co będzie podatne na błędy i trudne do zaktualizowania?

Odpowiedzi:


132

Wyrażenie regularne, którego szukasz, będzie najprawdopodobniej ogromne i koszmar w utrzymaniu, szczególnie dla osób, które nie są zaznajomione z wyrażeniami regularnymi.

Myślę, że łatwiej byłoby rozbić swoje wyrażenie regularne i robić to po kawałku. Może to zająć trochę więcej czasu, ale jestem prawie pewien, że utrzymanie go i debugowanie byłoby łatwiejsze. Umożliwiłoby to również przekazywanie użytkownikom bardziej ukierunkowanych komunikatów o błędach (innych niż tylko Invalid Password), co powinno poprawić komfort użytkowania.

Z tego, co widzę, dość biegle posługujesz się wyrażeniami regularnymi, więc przypuszczam, że podawanie wyrażeń regularnych do robienia tego, czego potrzebujesz, byłoby daremne.

Widząc twój komentarz, tak bym się do tego zabrał:

  • Musi mieć osiem znaków długości: nie potrzebujesz do tego wyrażenia regularnego. Korzystanie z .Lengthnieruchomości powinno wystarczyć.

  • W tym jedna wielka litera: możesz użyć [A-Z]+wyrażenia regularnego. Jeśli ciąg zawiera co najmniej jedną wielką literę, to wyrażenie regularne da wynik true.

  • Jeden znak specjalny: możesz użyć, \Wktóry będzie pasował do dowolnego znaku, który nie jest literą ani cyfrą, albo możesz użyć czegoś takiego, [!@#]aby określić niestandardową listę znaków specjalnych. Zauważ jednak, że znaki takie jak $, ^, (i )są znaki specjalne w języku wyrażeń regularnych, więc muszą być uciekł tak: \$. Krótko mówiąc, możesz użyć \W.

  • Znaki alfanumeryczne: użycie znaku \w+powinno odpowiadać dowolnej literze i cyfrze oraz podkreśleniu.

Zapoznaj się z tym samouczkiem, aby uzyskać więcej informacji.


2
nie napisałem tego samodzielnie, dostaję to od google drogi przyjacielu
Rania Umair

4
@RaniaUmair: Myślę, że twój komentarz potwierdza mój punkt widzenia. Zalecałbym rozbicie go tak, jak wskazałem.
npinti

35
+1 Regex jest potężny, ale nie miał rozwiązać żadnego problemu we wszechświecie
Cristian Lupascu

@ w0lf: Nie mogłem się bardziej zgodzić. Regex jest potężny, jednak zbyt szybko staje się zbyt złożony, więc lepiej go uprościć.
npinti

możesz mi pomóc muszę regx które akceptują przynajmniej jeden numer i maksymalnie 3 inne charecters może być cokolwiek
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

W jednej linii:

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

Edycja 2019-05-28:

Musisz dopasować cały ciąg wejściowy. Możesz więc ująć wyrażenie regularne między ^i, $aby zapobiec przypadkowemu przyjęciu częściowych dopasowań jako pasujących do całego wejścia:

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

Źródła:


58
Ponieważ składa się z 12 znaków
mmdemirbas

jeszcze jeden warunek nie powinien zaczynać się od cyfry, jak mogę to zrobić?
Lijo,

7
Zamiast tego możesz skrócić go za pomocą {8}, aby dopasować 8 znaków
Angelo Tricarico

jego dopasowanie do $ 1eerrrrrrr .. nie ma dużej litery.
Shilpi Jaiswal

@ShilpiJaiswal Albo używasz flagi do dopasowania bez uwzględniania wielkości liter, albo wykonujesz „znajdź” zamiast „dopasuj”. Aby upewnić się, że dopasowujesz cały ciąg wejściowy, możesz ująć wyrażenie regularne między ^a $. Spróbuj tego:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Tak wiele odpowiedzi ... wszystkie złe!

Wyrażenia regularne nie mają operatora AND, więc dość trudno jest napisać wyrażenie regularne pasujące do prawidłowych haseł, gdy ważność jest definiowana przez coś ORAZ coś innego ORAZ coś innego ...

Ale, wyrażenia regularne zrobić mieć operator OR, więc wystarczy zastosować twierdzenie DeMorgan, a napisać regex, który pasuje nieprawidłowych haseł.

wszystko, co ma mniej niż 8 znaków LUB cokolwiek bez cyfr LUB cokolwiek bez wielkich liter LUB cokolwiek bez znaków specjalnych

Więc:

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

Jeśli cokolwiek pasuje do tego, jest to nieprawidłowe hasło.


3
Gdyby OP chciał dokładnie 8 znaków, musiałbyś to dodać |.{9,}. +1 za koncepcję
Daniel

Świetne i proste rozwiązanie tego pytania, chociaż zgadzam się, że jedno wyrażenie regularne nie jest optymalne dla konkretnego problemu.
Siderite Zackwehdex

1
Wyrażenia regularne nie mieć i operatorzy, są one nazywane uprzedzona / lookbehind twierdzeń.
stosunkowo_random

13

Odpowiedź brzmi: nie używaj wyrażenia regularnego. To jest zestawy i liczenie.

Wyrażenia regularne dotyczą porządku.

W swoim życiu jako programista będziesz proszony o zrobienie wielu rzeczy, które nie mają sensu. Naucz się kopać poziom głębiej. Dowiedz się, kiedy pytanie jest błędne.

Pytanie (jeśli wspomniało o wyrażeniach regularnych) jest błędne.

Pseudokod (ostatnio przełączałem się między zbyt wieloma językami):

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)

Założę się, że przeczytałeś i zrozumiałeś powyższy kod niemal natychmiast. Założę się, że zajęło ci to dużo więcej czasu z wyrażeniem regularnym i masz mniejszą pewność, że jest poprawne. Rozszerzanie wyrażenia regularnego jest ryzykowne. Rozszerzyłem bezpośrednio powyższe, znacznie mniej.

Zwróć również uwagę, że pytanie jest sformułowane nieprecyzyjnie. Czy zestaw znaków to ASCII czy Unicode, czy ?? Po przeczytaniu pytania domyślam się, że zakłada się co najmniej jedną małą literę. Więc myślę, że zakładaną ostatnią zasadą powinno być:

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

(Zmiana kapeluszy na skoncentrowaną na bezpieczeństwie, jest to naprawdę irytująca / nieprzydatna zasada).

Wiedza, kiedy pytanie jest błędne, jest znacznie ważniejsza niż mądre odpowiedzi. Sprytna odpowiedź na złe pytanie jest prawie zawsze błędna.


2
Zgadzam się. Im więcej osób z którymi pracujesz, tym więcej kodu musi być czytelne, chociaż niektóre implementacje
wyrażeń regularnych,

Podoba mi się, że niektórzy użytkownicy, tacy jak Ty, mają odwagę powiedzieć, że Regex nie zawsze jest lepszym rozwiązaniem do zastosowania i że czasami proste programowanie jest bardziej czytelne.
schlebe

12

Jako przykład, jak można to zrobić za pomocą czytelnego / możliwego do utrzymania wyrażenia regularnego.

W przypadku dłuższych RegexOptions.IgnorePatternWhitespacewyrażeń regularnych należy zawsze używać znaków, które pozwolą na użycie białych znaków i komentarzy w wyrażeniu, aby zapewnić lepszą czytelność.

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

Jest to najlepszy sposób na wykorzystanie lookahead assertionwzorca „i” w celu pokrycia całego ograniczenia w ramach jednego wyrażenia regularnego. Działa dla większej liczby ograniczeń i można je łatwo wygenerować, jeśli niektóre ograniczenia powinny być włączone / wyłączone przez konfigurację.
dognose

2
Zastosowanie kategorii Unicode to doskonały pomysł. Świat jest szerszy niż ASCII!
Walter Tross

1

Jeśli potrzebujesz tylko jednej dużej litery i znaku specjalnego, to powinno działać:

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

Ciąg AAaaaaaaa#nie jest OK zgodnie z tym wyrażeniem
Cristian Lupascu

3
Cóż, ma 10, a nie 8 znaków i zawiera więcej niż jedną wielką
literę

4
Masz rację, to nie powiedzieć, to w pytaniu. Myślałem, że te reguły bardziej przypominają „przynajmniej jedną wielką literę” zamiast „dokładnie jedną wielką” . Nie jestem pewien, czy tego właśnie chciał OP.
Cristian Lupascu


0

To pytanie zaczyna być wirusowe i pojawiło się wiele ciekawych sugestii.

Tak, pisanie odręczne jest trudne. Więc łatwiejszym rozwiązaniem jest użycie szablonu. Chociaż wynikowe wyrażenie regularne może nie być najbardziej optymalne, łatwiej będzie je utrzymać i / lub zmienić, a użytkownik będzie miał lepszą kontrolę nad wynikiem. Możliwe, że coś przeoczyłem, więc jakakolwiek konstruktywna krytyka będzie pomocna.

Te linki mogą być interesujące: dopasuj co najmniej 2 cyfry 2 litery w dowolnej kolejności w ciągu , język wyrażeń regularnych , grupy przechwytywania

Używam tego szablonu (?=(?:.*?({type})){({count})})na podstawie wszystkich wyrażeń regularnych, które widziałem w SO. Następnym krokiem jest zastąpienie potrzebnego wzoru ( number, special character...) i dodanie konfiguracji długości.

Stworzyłem małą klasę do tworzenia wyrażenia regularnego PasswordRegexGenerator.cs Przykład:

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

Możesz użyć poniższej klasy do walidacji:

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

  }
}

gdzie 6 i 20 to minimalna i maksymalna długość hasła.


0
  • Użyj wyrażenia bez śledzenia wstecznego, aby najpierw dopasować całe hasło, jeśli ma ono co najmniej 8 znaków (w ten sposób nie ma eksplozji kombinatorycznej przez długie, ale nieprawidłowe hasła): (?>{8,})
  • Użyj asercji lookbehind, aby sprawdzić obecność wszystkich wymaganych znaków (warunki AND). (?<=...)
  • Co najmniej jedna wielka litera: (?<=\p{Lu}.*)
  • Co najmniej jeden znak specjalny (trochę niejednoznaczny, ale nie używajmy słowa): (?<=\W.*)
  • Co najmniej jeden znak alfanumeryczny (: (?<=\w.*)

Podsumował:

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


0

Najlepiej nie używać wyrażeń regularnych do wszystkiego. Te wymagania są bardzo lekkie. W przypadku operacji na łańcuchach opartych na procesorach w celu sprawdzenia kryteriów / walidacji jest znacznie tańsza i szybsza niż regex!


0

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>


Chociaż ten fragment kodu może rozwiązać problem, nie wyjaśnia, dlaczego ani jak odpowiada na pytanie. Dołącz wyjaśnienie swojego kodu , ponieważ naprawdę pomaga to poprawić jakość Twojego postu. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod. Możesz użyć przycisku edycji , aby poprawić tę odpowiedź, aby uzyskać więcej głosów i reputacji!
Brian Tompsett - 汤 莱恩

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

15
Proponuję zredagować swoje pytanie i dołączyć wyjaśnienia. Odpowiedzi zawierające tylko kod są czasami wystarczające, ale odpowiedzi z kodem + wyjaśnieniem są zawsze lepsze
Barranka
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.