Alle zuvor gegebenen Antworten verwenden dieselbe (richtige) Technik, um für jede Anforderung einen eigenen Lookahead zu verwenden. Sie enthalten jedoch einige Ineffizienzen und einen potenziell massiven Fehler, abhängig vom Back-End, das das Kennwort tatsächlich verwendet.
Ich beginne mit dem regulären Ausdruck der akzeptierten Antwort:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Erstens, da Java unterstützt \A
und \z
ich diese lieber verwende, um sicherzustellen, dass die gesamte Zeichenfolge unabhängig von validiert wird Pattern.MULTILINE
. Dies wirkt sich nicht auf die Leistung aus, vermeidet jedoch Fehler beim Recycling von Regexen.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Das Überprüfen, ob das Kennwort kein Leerzeichen enthält, und das Überprüfen seiner Mindestlänge können in einem einzigen Durchgang durchgeführt werden, indem alle auf einmal verwendet werden, indem ein variabler Quantifizierer {8,}
in die Kurzform eingefügt wird \S
, die die zulässigen Zeichen begrenzt:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Wenn das angegebene Kennwort ein Leerzeichen enthält, werden alle Überprüfungen durchgeführt, sodass die endgültige Überprüfung des Leerzeichens fehlschlägt. Dies kann vermieden werden, indem alle Punkte durch Folgendes ersetzt werden \S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
Der Punkt sollte nur verwendet werden, wenn Sie wirklich ein Zeichen zulassen möchten. Verwenden Sie andernfalls eine (negierte) Zeichenklasse, um Ihren regulären Ausdruck nur auf die Zeichen zu beschränken, die wirklich zulässig sind. Obwohl es in diesem Fall kaum einen Unterschied macht, ist es eine sehr gute Angewohnheit , den Punkt nicht zu verwenden, wenn etwas anderes angemessener ist. Ich sehe viel zu viele Fälle von katastrophalem Backtracking, weil der Entwickler zu faul war, um etwas passenderes als den Punkt zu verwenden.
Da es eine gute Chance gibt, dass die ersten Tests in der ersten Hälfte des Passworts ein geeignetes Zeichen finden, kann ein fauler Quantifizierer effizienter sein:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Aber jetzt zum wirklich wichtigen Thema: Keine der Antworten erwähnt die Tatsache, dass die ursprüngliche Frage von jemandem geschrieben zu sein scheint, der in ASCII denkt. Aber in Java sind Strings Unicode. Sind Nicht-ASCII-Zeichen in Passwörtern zulässig? Wenn dies der Fall ist, sind nur ASCII-Leerzeichen nicht zulässig, oder sollten alle Unicode-Leerzeichen ausgeschlossen werden.
Standardmäßig werden \s
nur ASCII-Leerzeichen abgeglichen, sodass die Umkehrung \S
mit allen Unicode-Zeichen (Leerzeichen oder nicht) und allen Nicht-Leerzeichen-ASCII-Zeichen übereinstimmt. Wenn Unicode-Zeichen zulässig sind, Unicode-Leerzeichen jedoch nicht, kann das UNICODE_CHARACTER_CLASS
Flag angegeben werden, \S
um Unicode-Leerzeichen auszuschließen. Wenn Unicode-Zeichen nicht zulässig sind, [\x21-\x7E]
können sie stattdessen verwendet werden \S
, um alle ASCII-Zeichen abzugleichen, die kein Leerzeichen oder Steuerzeichen sind.
Das bringt uns zum nächsten möglichen Problem: Wollen wir Steuerzeichen zulassen? Der erste Schritt beim Schreiben eines richtigen regulären Ausdrucks besteht darin, genau anzugeben, was Sie abgleichen möchten und was nicht. Die einzige technisch korrekte Antwort von 100% ist, dass die Kennwortspezifikation in der Frage nicht eindeutig ist, da nicht angegeben wird, ob bestimmte Zeichenbereiche wie Steuerzeichen oder Nicht-ASCII-Zeichen zulässig sind oder nicht.