Regex найти 3 из 4 условий

Мой клиент запросил, чтобы пароли в своей системе должны следовать определенному набору правил проверки, и у меня возникают большие трудности с "хорошим" регулярным выражением.

Правила, которые мне даны,...

  • Минимум 8 символов
  • Разрешить любой символ
  • Должен иметь хотя бы один экземпляр из трех из четырех следующих типов символов...
    • Символ верхнего регистра
    • Нижний регистр символов
    • Числовая цифра
    • "Специальный символ"

Когда я нажал больше, "Специальные символы" буквально все остальное (включая пробелы).

Я могу легко проверить хотя бы один экземпляр для всех четырех, используя следующее...

^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)(?=.*?[^a-zA-Z0-9]).{8,}$

Следующие работы, но это ужасно и грязно...

^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?\d)(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?\d)(?=.*?[^a-zA-Z0-9])).{8,}$

Таким образом, вам не нужно самостоятельно его выполнять, выше проверяется (1,2,3|1,2,4|1,3,4|2,3,4), которые являются 4 возможными комбинациями из 4 групп (где число относится к "типам" в наборе правил).

Есть ли "более приятный", более чистый или простой способ сделать это?

(Обратите внимание: это будет использоваться в элементе управления <asp:RegularExpressionValidator> на веб-сайте ASP.NET, поэтому должно быть допустимым регулярным выражением для .NET и javascript.)

Ответ 1

Это не очень лучшее решение, но вы можете уменьшить [^a-zA-Z0-9] до [\W_], поскольку символ слова - это все буквы, цифры и символ подчеркивания. Я не думаю, что вы можете избежать чередования при попытке сделать это в одном регулярном выражении. Я думаю, что у вас есть лучшее решение.

Одна небольшая оптимизация - это \d*[a-z]\w_*|\d*[A-Z]\w_* ~ > \d*[a-zA-Z]\w_*, поэтому я могу удалить один из наборов чередования. Если вы разрешили только 3 из 4, это не сработало бы, но поскольку \d*[A-Z][a-z]\w_* было неявно разрешено, он работает.

(?=.{8,})((?=.*\d)(?=.*[a-z])(?=.*[A-Z])|(?=.*\d)(?=.*[a-zA-Z])(?=.*[\W_])|(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_])).*

Расширенная версия:

(?=.{8,})(
  (?=.*\d)(?=.*[a-z])(?=.*[A-Z])|
  (?=.*\d)(?=.*[a-zA-Z])(?=.*[\W_])|
  (?=.*[a-z])(?=.*[A-Z])(?=.*[\W_])
).*

REY

Ответ 2

Вышеупомянутое Regex хорошо работало для большинства сценариев, за исключением строк, таких как "AAAAAA1 $", "$$$$$$ 1a", Это может быть проблемой только в iOS (Objective C и Swift), которые возникают в регулярном выражении "\ d" Следующее исправление работало в iOS, т.е. изменилось на [0-9] для цифр

^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])).{8,}$

Ответ 3

Я хотел бы улучшить принятое решение с помощью этого

^(?=.{8,})(
    (?=.*[^a-zA-Z\s])(?=.*[a-z])(?=.*[A-Z])|
    (?=.*[^a-zA-Z0-9\s])(?=.*\d)(?=.*[a-zA-Z])
).*$