Wszystkie udzielone wcześniej odpowiedzi wykorzystują tę samą (poprawną) technikę, aby użyć osobnego wyprzedzenia dla każdego wymagania. Ale zawierają kilka nieefektywności i potencjalnie ogromny błąd, w zależności od zaplecza, które faktycznie będzie używać hasła.
Zacznę od wyrażenia regularnego z zaakceptowanej odpowiedzi:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Przede wszystkim, ponieważ Java obsługuje \A
i \z
wolę ich używać, aby upewnić się, że cały ciąg jest zweryfikowany, niezależnie od Pattern.MULTILINE
. Nie wpływa to na wydajność, ale pozwala uniknąć błędów podczas odtwarzania wyrażeń regularnych.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Sprawdzenie, czy hasło nie zawiera białych znaków i sprawdzenie jego minimalnej długości, można wykonać w jednym przebiegu, używając funkcji all na raz, umieszczając zmienny kwantyfikator {8,}
w skrócie, \S
który ogranicza dozwolone znaki:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Jeśli podane hasło zawiera spację, wszystkie sprawdzenia zostaną wykonane, tylko po to, aby ostatnie sprawdzenie miejsca zakończyło się niepowodzeniem. Można tego uniknąć, zastępując wszystkie kropki \S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
Kropki należy używać tylko wtedy, gdy naprawdę chcesz dopuścić dowolny znak. W przeciwnym razie użyj (zanegowanej) klasy znaków, aby ograniczyć swoje wyrażenie regularne tylko do tych znaków, które są naprawdę dozwolone. Chociaż w tym przypadku nie ma to większego znaczenia, nieużywanie kropki, gdy coś innego jest bardziej odpowiednie, jest bardzo dobrym nawykiem. Widzę zbyt wiele przypadków katastrofalnego cofania się, ponieważ programista był zbyt leniwy, aby użyć czegoś bardziej odpowiedniego niż kropka.
Ponieważ istnieje duża szansa, że początkowe testy znajdą odpowiedni znak w pierwszej połowie hasła, leniwy kwantyfikator może być bardziej wydajny:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Ale teraz przejdźmy do naprawdę ważnej kwestii: żadna z odpowiedzi nie wspomina o tym, że pierwotne pytanie wydaje się być napisane przez kogoś, kto myśli w ASCII. Ale w Javie ciągi znaków to Unicode. Czy w hasłach dozwolone są znaki spoza zestawu ASCII? Jeśli tak, są dozwolone tylko spacje ASCII lub należy wykluczyć wszystkie białe spacje Unicode.
Domyślnie \s
dopasowuje tylko białe znaki ASCII, więc jego odwrotność \S
dopasowuje wszystkie znaki Unicode (białe lub nie) i wszystkie znaki ASCII niebędące białymi znakami. Jeśli znaki Unicode są dozwolone, ale spacje Unicode nie są, UNICODE_CHARACTER_CLASS
można określić flagę, aby \S
wykluczyć białe znaki Unicode. Jeśli znaki Unicode nie są dozwolone, [\x21-\x7E]
można ich użyć zamiast \S
znaku ASCII, które nie są spacjami ani znakami sterującymi.
Co prowadzi nas do następnego potencjalnego problemu: czy chcemy pozwolić postaciom sterującym? Pierwszym krokiem w tworzeniu odpowiedniego wyrażenia regularnego jest dokładne określenie, co chcesz dopasować, a czego nie. Jedyną w 100% poprawną technicznie odpowiedzią jest to, że specyfikacja hasła w pytaniu jest niejednoznaczna, ponieważ nie określa, czy niektóre zakresy znaków, takie jak znaki sterujące lub znaki spoza zestawu ASCII, są dozwolone, czy nie.