Espressione regolare per verificare se la password è "8 caratteri di cui 1 lettera maiuscola, 1 carattere speciale, caratteri alfanumerici"


102

Voglio un'espressione regolare per verificarlo

una password deve contenere otto caratteri, inclusa una lettera maiuscola, un carattere speciale e caratteri alfanumerici.

Ed ecco la mia espressione di convalida che è per otto caratteri tra cui una lettera maiuscola, una lettera minuscola e un numero o un carattere speciale.

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

Come posso scriverlo per una password che deve essere di otto caratteri tra cui una lettera maiuscola, un carattere speciale e caratteri alfanumerici?


26
Perché hai bisogno di un'espressione regolare per questo? Un'espressione regolare completa che soddisfi le tue esigenze sarà molto lunga e complessa. È più facile scrivere i vincoli nel codice C #.
Greg Hewgill,

32
Hai preso in considerazione la verifica di una password complessa, invece di verificare che la password soddisfi alcune regole arbitrarie che sono un proxy imperfetto per una password complessa? Ci sono molte librerie e programmi che, se inseriti con una password, ne determineranno la forza.
Wayne Conrad,

4
@GregHewgill Vorrei votare a favore del tuo commento se potessi :-) Questo sembra un altro caso di "se tutto quello che hai è un martello, tutto comincia a sembrare un chiodo".
Christian.K

3
Ti serve esattamente un carattere maiuscolo / speciale o almeno uno?
mmdemirbas

4
Per esigenza dell'utente, intendi che il tuo utente sta dettando i dettagli di implementazione? Forse dovrebbero codificarlo da soli, allora. Ad essere onesti, penso che sarebbe più facile mantenere e capire se avessi creato dei segnalini e controllato ogni carattere uno per uno, incrementando i contatori appropriati per ogni personaggio che corrisponde a una regola. Da un punto di vista tecnico non è qualcosa che impressionerà nessuno, ma perché complicare le cose con qualcosa che sarà soggetto a errori e difficile da aggiornare?

Risposte:


132

L'espressione regolare che stai cercando sarà molto probabilmente enorme e un incubo da mantenere, specialmente per le persone che non hanno molta familiarità con le espressioni regolari.

Penso che sarebbe più facile scomporre la tua regex e farlo un po 'alla volta. Potrebbe volerci un po 'di più da fare, ma sono abbastanza sicuro che mantenerlo e debug sarebbe più facile. Ciò consentirebbe anche di fornire messaggi di errore più diretti ai tuoi utenti (oltre al semplice Invalid Password) che dovrebbero migliorare l'esperienza dell'utente.

Da quello che vedo sei abbastanza fluente in regex, quindi presumo che darti le espressioni regolari per fare ciò di cui hai bisogno sarebbe inutile.

Vedendo il tuo commento, ecco come lo farei:

  • Deve essere lungo otto caratteri: non è necessaria una regex per questo. Usare la .Lengthproprietà dovrebbe essere sufficiente.

  • Includere una lettera maiuscola: puoi usare l' [A-Z]+espressione regolare. Se la stringa contiene almeno una lettera maiuscola, questa espressione regolare produrrà true.

  • Un carattere speciale: puoi usare il \Wche corrisponderà a qualsiasi carattere che non sia una lettera o un numero oppure puoi usare qualcosa di simile [!@#]per specificare un elenco personalizzato di caratteri speciali. Nota però che personaggi come $, ^, (e )sono caratteri speciali nel linguaggio delle espressioni regolari, quindi hanno bisogno di essere sfuggito in questo modo: \$. Quindi, in breve, potresti usare il file \W.

  • Caratteri alfanumerici: l'utilizzo di \w+deve corrispondere a qualsiasi lettera, numero e trattino basso.

Dai un'occhiata a questo tutorial per maggiori informazioni.


2
non l'ho scritto da solo, l'ho preso da google caro amico
Rania Umair

4
@RaniaUmair: penso che il tuo commento dimostri il mio punto di vista. Ti consiglierei di scomporlo come ho specificato.
npinti

35
+1 Regex è potente, ma non era pensato per risolvere alcun problema nell'universo
Cristian Lupascu,

@ w0lf: non potrei essere più d'accordo. Regex è potente, tuttavia, diventa troppo complesso troppo velocemente, quindi è meglio mantenerlo semplice.
npinti

puoi aiutarmi, ho bisogno di un regx che accetti almeno un numero e al massimo altri 3 caratteri possono essere qualsiasi cosa
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

In una riga:

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

Modifica 2019-05-28:

È necessario abbinare l'intera stringa di input. Quindi, puoi racchiudere la regex tra ^e $per evitare di assumere accidentalmente corrispondenze parziali come corrispondenti all'intero input:

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

fonti:


58
Perché è composto da 12 caratteri
mmdemirbas

un'altra condizione non dovrebbe iniziare con una cifra come posso farlo?
Lijo

7
Puoi accorciarlo utilizzando {8} invece di abbinare 8 caratteri
Angelo Tricarico

la sua corrispondenza per $ 1eerrrrrrr .. non ha lettere maiuscole.
Shilpi Jaiswal

@ShilpiJaiswal O stai usando un flag per la corrispondenza senza distinzione tra maiuscole e minuscole, o stai facendo una "ricerca" invece di "corrispondenza". Per assicurarti di far corrispondere l'intera stringa di input, puoi racchiudere la regex tra ^e $. Prova questo:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Tante risposte .... tutte pessime!

Le espressioni regolari non hanno un operatore AND, quindi è piuttosto difficile scrivere una regex che corrisponda a password valide, quando la validità è definita da qualcosa AND qualcos'altro AND qualcos'altro ...

Ma, le espressioni regolari fare avere un operatore OR, quindi basta applicare il teorema di De Morgan, e scrivere una regex che corrisponde non valide le password.

qualsiasi cosa con meno di 8 caratteri OPPURE qualsiasi cosa senza numeri OPPURE qualsiasi cosa senza maiuscole OPPURE qualsiasi cosa senza caratteri speciali

Così:

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

Se qualcosa corrisponde a questo, allora è una password non valida .


3
Se l'OP voleva esattamente 8 caratteri, quindi dovresti aggiungere |.{9,}. +1 per il concetto
Daniel

Ottima e semplice soluzione per la domanda, anche se sono d'accordo che un'unica espressione regolare non è quella ottimale per il problema reale.
Siderite Zackwehdex

1
Le espressioni regolari non hanno e gli operatori, si chiamano guardano avanti / lookbehind affermazioni.
relativamente_random

13

La risposta è non usare un'espressione regolare. Questo è set e conteggio.

Le espressioni regolari riguardano l'ordine.

Nella tua vita di programmatore ti verrà chiesto di fare molte cose che non hanno senso. Impara a scavare un livello più profondo. Impara quando la domanda è sbagliata.

La domanda (se menzionava espressioni regolari) è sbagliata.

Pseudocodice (è passato da troppe lingue, negli ultimi tempi):

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)

Scommetto che hai letto e capito il codice sopra quasi istantaneamente. Scommetto che hai impiegato molto più tempo con la regex e sei meno certo che sia corretto. Estendere la regex è rischioso. Esteso l'immediato sopra, molto meno.

Nota anche che la domanda è formulata in modo impreciso. Il set di caratteri è ASCII o Unicode o ?? La mia ipotesi dalla lettura della domanda è che si presume almeno un carattere minuscolo. Quindi penso che l'ultima regola presunta dovrebbe essere:

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

(Cambiare i cappelli a incentrati sulla sicurezza, questa è una regola davvero fastidiosa / non utile.)

Imparare a sapere quando la domanda è sbagliata è estremamente più importante delle risposte intelligenti. Una risposta intelligente alla domanda sbagliata è quasi sempre sbagliata.


2
Sono d'accordo. Più persone lavori con, più codice deve essere leggibile anche se alcune implementazioni di regexp che ho visto come risposte sono abbastanza chiare
Nicola Peluchetti

Mi piace che alcuni utenti come te abbiano il coraggio di dire che Regex non è sempre la soluzione migliore da applicare e che a volte, la semplice programmazione è più leggibile.
schlebe

12

Ad esempio come questo potrebbe essere fatto con una regex leggibile / gestibile.

Per RegexOptions.IgnorePatternWhitespaceun'espressione regolare più lunga dovresti sempre usare per consentire spazi bianchi e commenti nell'espressione per una migliore leggibilità.

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

Questo è il modo migliore per abusare del lookahead assertiontipo di pattern "e" per coprire l'intero vincolo all'interno di una singola regex. Funziona per più vincoli e può essere facilmente generato se alcuni vincoli devono essere abilitati / disabilitati dalla configurazione.
dognose

2
L'uso delle categorie Unicode è un'ottima idea. Il mondo è più ampio di ASCII!
Walter Tross

1

Se hai bisogno di una sola maiuscola e di un carattere speciale, dovrebbe funzionare:

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

La stringa AAaaaaaaa#non è OK secondo questa espressione
Cristian Lupascu

3
Bene, è lungo 10, non 8 caratteri e contiene più di un ultimo maiuscolo, quindi dovrebbe fallire ...
user1096188

4
Hai ragione, ma non dice questo nella questione. Pensavo che queste regole fossero più come "almeno una maiuscola" invece di "esattamente una maiuscola" . Non sono sicuro che sia quello che volesse l'OP.
Cristian Lupascu


0

Questa domanda inizia ad essere virale e sono apparsi molti suggerimenti interessanti.

Sì, scrivere a mano è difficile. Quindi una soluzione più semplice è usare un modello. Sebbene la regex risultante possa non essere la più ottimale, sarà più facile mantenerla e / o modificarla e l'utente avrà un migliore controllo sul risultato. È possibile che mi sia perso qualcosa, quindi qualsiasi critica costruttiva sarà utile.

Questi collegamenti potrebbero essere interessanti: abbina almeno 2 cifre 2 lettere in qualsiasi ordine in una stringa , Linguaggio delle espressioni regolari , Cattura di gruppi

Sto usando questo modello (?=(?:.*?({type})){({count})})basato su tutte le espressioni regolari che ho visto in SO. Il passaggio successivo è la sostituzione del modello necessario ( number, special character...) e l'aggiunta della configurazione per la lunghezza.

Ho creato una piccola classe per comporre la regex PasswordRegexGenerator.cs Un esempio:

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

È possibile utilizzare la seguente classe per la convalida:

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

  }
}

dove 6 e 20 sono la lunghezza minima e massima della password.


0
  • Usa un'espressione non di backtracking per abbinare prima l'intera password, se ha almeno 8 caratteri (in questo modo, non c'è esplosione combinatoria per password lunghe, ma non valide): (?>{8,})
  • Utilizza le asserzioni lookbehind per verificare la presenza di tutti i caratteri richiesti (condizioni AND). (?<=...)
  • Almeno un carattere maiuscolo: (?<=\p{Lu}.*)
  • Almeno un carattere speciale (un po 'ambiguo, ma usiamo non-parola): (?<=\W.*)
  • Almeno un carattere alfanumerico (: (?<=\w.*)

Riassunto:

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


0

La cosa migliore è non usare le espressioni regolari per tutto. Questi requisiti sono molto leggeri. Sulle operazioni sulle stringhe dal punto di vista della CPU per il controllo dei criteri / convalida è molto più economico e veloce di regex!


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

15
Ti suggerisco di modificare la tua domanda e di includere qualche spiegazione. Le risposte di solo codice a volte sono abbastanza buone, ma le risposte di codice + spiegazione sono sempre migliori
Barranka
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.