Все ранее предоставленные ответы используют одну и ту же (правильную) технику, чтобы использовать отдельное предпросмотр для каждого требования.Но они содержат несколько недостатков и потенциально серьезную ошибку, в зависимости от серверной части, которая будет фактически использовать пароль.
Я начну с регулярного выражения из принятого ответа:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Прежде всего, поскольку Java поддерживает \A
и \z
, я предпочитаю использовать их, чтобы убедиться, что вся строка проверена, независимо от Pattern.MULTILINE
.Это не влияет на производительность, но позволяет избежать ошибок при повторном использовании регулярных выражений.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Проверка того, что пароль не содержит пробелов, и проверка его минимальной длины можно выполнить за один проход, используя все сразупоместив переменный квантификатор {8,}
на сокращение \S
, ограничивающее допустимые символы:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Если указанный пароль содержит пробел, все проверки будут выполнены только для окончательной проверкипровалиться на месте.Этого можно избежать, заменив все точки на \S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
Точку следует использовать, только если вы действительно хотите разрешить какой-либо символ.В противном случае используйте (отрицательный) класс символов, чтобы ограничить свое регулярное выражение только теми символами, которые действительно разрешены.Хотя в этом случае это не имеет большого значения, не использовать точку, когда что-то более подходящее - очень хорошая привычка.Я вижу слишком много случаев катастрофического возврата назад , потому что разработчик был слишком ленив, чтобы использовать что-то более подходящее, чем точка.
Так как есть хорошие шансы, начальные тесты найдут подходящий символ впервая половина пароля, ленивый квантификатор может быть более эффективным:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Но теперь для действительно важного вопроса: ни один из ответов не упоминает тот факт, что первоначальный вопрос, кажется, написан кем-то, ктодумает в ASCII.Но в Java строки являются Unicode.Разрешены ли символы не ASCII в паролях?Если они есть, запрещены только пробелы ASCII или должны быть исключены все пробелы Unicode.
По умолчанию \s
соответствует только пробелам ASCII, поэтому его обратный \S
соответствует всем символам Unicode (пробелам или нет) ивсе непробельные символы ASCII.Если символы Юникода разрешены, а пробелы Юникода - нет, можно указать флаг UNICODE_CHARACTER_CLASS
, чтобы \S
исключал пробелы Юникода.Если символы Unicode недопустимы, вместо \S
можно использовать [\x21-\x7E]
, чтобы сопоставить все символы ASCII, которые не являются пробелами или управляющими символами.
Что приводит нас к следующей потенциальной проблеме: doмы хотим разрешить управляющие символы?Первый шаг в написании правильного регулярного выражения - точно указать, что вы хотите сопоставить, а что нет.Единственно на 100% технически правильный ответ заключается в том, что спецификация пароля в вопросе неоднозначна, поскольку в ней не указывается, разрешены ли определенные диапазоны символов, такие как управляющие символы или символы, не входящие в ASCII.