Espressione regolare per imporre password complesse, corrispondenti a 3 regole su 4

Ho i seguenti criteri per creare un’espressione regolare per una password che sia conforms alle seguenti regole:

  1. La password deve essere lunga 8 caratteri (ciò che posso fare :-)).

La password deve quindi contenere caratteri di almeno 3 delle seguenti 4 regole:

  1. Lettere maiuscole
  2. Minuscolo
  3. Numeri
  4. Non alfa numerico

Posso fare in modo che l’espressione corrisponda a TUTTE quelle regole con la seguente espressione:

/^(?=.*\d)(?=.*[az])(?=.*[AZ])(?=.[\W]).{8,}$/ 

Ma sto lottando su come farlo in modo tale da dover risolvere solo 3 delle 4 regole.

Qualcuno può aiutarmi con questo?

Non usare una regex per controllarla allora.

 if (password.length < 8) alert("bad password"); var hasUpperCase = /[AZ]/.test(password); var hasLowerCase = /[az]/.test(password); var hasNumbers = /\d/.test(password); var hasNonalphas = /\W/.test(password); if (hasUpperCase + hasLowerCase + hasNumbers + hasNonalphas < 3) alert("bad password"); 

Se devi usare una singola regex:

 ^(?:(?=.*[az])(?:(?=.*[AZ])(?=.*[\d\W])|(?=.*\W)(?=.*\d))|(?=.*\W)(?=.*[AZ])(?=.*\d)).{8,}$ 

Questa regex non è ottimizzata per l'efficienza. È costruito da A·B·C + A·B·D + A·C·D + B·C·D con una certa fattorizzazione. Abbattersi:

 ^ (?: (?=.*[az]) # 1. there is a lower-case letter ahead, (?: # and (?=.*[AZ]) # 1.ai) there is also an upper-case letter, and (?=.*[\d\W]) # 1.a.ii) a number (\d) or symbol (\W), | # or (?=.*\W) # 1.bi) there is a symbol, and (?=.*\d) # 1.b.ii) a number ahead ) | # OR (?=.*\W) # 2.a) there is a symbol, and (?=.*[AZ]) # 2.b) an upper-case letter, and (?=.*\d) # 2.c) a number ahead. ) .{8,} # the password must be at least 8 characters long. $ 

Potresti scrivere una regex davvero sofisticata per farlo. Invece, suggerirei di scrivere quattro regex distinte, una per ogni regola, e testarle una alla volta, contando quante di esse corrispondono. Se tre su quattro ha fatto, accetta la password.

Puoi usare il seguente Regex:

 (^(?=.*\d)(?=.*[az])(?=.*[AZ]).*$)?(^(?=.*\d)(?=.*[az])(?=.*[@#$%^&+=]).*$)?(^(?=.*\d)(?=.*[AZ])(?=.*[@#$%^&+=]).*$)?(^(?=.*[az])(?=.*[AZ])(?=.*[@#$%^&+=]).*$)? 

Con una lunghezza minima della password di 8 e lunghezza massima 32 è ansible utilizzare il seguente Regex:

 (^(?=.*\d)(?=.*[az])(?=.*[AZ]).{8,32}$)?(^(?=.*\d)(?=.*[az])(?=.*[@#$%^&+=]).{8,32}$)?(^(?=.*\d)(?=.*[AZ])(?=.*[@#$%^&+=]).{8,32}$)?(^(?=.*[az])(?=.*[AZ])(?=.*[@#$%^&+=]).{8,32}$)? 

Id suggerisco di fare i controlli separatamente, e quindi di totalizzare il numero di corrispondenze.

(Non userei anche una regex in nessuna di esse, ma questo è solo il mio POV personale – cioè che ostacolano la leggibilità e sono in genere codice di sola scrittura)