Все ранее приведенные ответы используют ту же (правильную) технику, чтобы использовать отдельный просмотр для каждого требования. Но они содержат пару неэффективности и потенциально массивную ошибку, в зависимости от того, что на самом деле будет использовать пароль.
Начну с регулярным выражением из принятого ответа:
^(?=.*[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
Точка должна использоваться только если вы действительно хотите, чтобы любой символ. В противном случае используйте (отрицаемый) класс символов, чтобы ограничить регулярное выражение только теми символами, которые действительно разрешены. Хотя в этом случае мало что имеет значения, not using the dot when something else is more appropriate - очень хорошая привычка. Я вижу слишком много случаев catastrophic backtracking, потому что разработчику было слишком ленив, чтобы использовать что-то более подходящее, чем точка.
Поскольку есть хороший шанс, первоначальные тесты будут найти соответствующий символ в первой половине пароля, ленивый квантор может быть более эффективным:
\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 разрешены, а в Unicode - нет, можно указать флаг UNICODE_CHARACTER_CLASS
, чтобы сделать \S
исключать пробелы Unicode. Если символы Unicode не разрешены, то [\x21-\x7E]
может использоваться вместо \S
для соответствия всем символам ASCII, которые не являются пробелом или символом управления.
Это приводит нас к следующей потенциальной проблеме: хотим ли мы разрешать контрольные символы? Первым шагом в написании правильного регулярного выражения является точное указание того, что вы хотите сопоставить, а что нет. Единственный 100% -ный технически правильный ответ заключается в том, что спецификация пароля в вопросе неоднозначна, поскольку она не указывает, разрешены ли определенные диапазоны символов, например, управляющие символы или символы, отличные от ASCII, или нет.
правила Пароль плохо. Для получения дополнительной информации см. [Справка - Проверка пароля] (https://stackoverflow.com/questions/48345922/reference-password-validation). – ctwheels