Что такое регулярное выражение для следующего ограничения? - PullRequest
1 голос
/ 26 мая 2011

Мне нужно регулярное выражение для строки для пароля, которая содержит как минимум три из следующих четырех типов символов:

  • Английские строчные буквы (от a до z).
  • АНГЛИЙСКИЕ ПЕРСОНАЖНЫЕ СИМВОЛЫ (ОТ ЧЕРЕЗ Z).
  • Базовые 10 цифр (от 0 до 9).
  • Не буквенно-цифровые символы (например,!, $, #,%).

И должен содержать не менее 8 символов.

Ответы [ 5 ]

10 голосов
/ 26 мая 2011

Учитывая чудовищность a , которую могут сгенерировать эти требования, я подозреваю, что на самом деле вам будет лучше делать это как множественные проверки, что-то вроде (псевдокод ):

def check_password (s):
    if len(s) < 8:
        return false
    rules_followed = 0
    if match (s, "[a-z]") rules_followed++;
    if match (s, "[A-Z]") rules_followed++;
    if match (s, "[0-9]") rules_followed++;
    if match (s, "[!$#%]") rules_followed++;  # et cetera
    if rules_followed < 3:
        return false
    return true

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

Теперь я понимаю, что это не всегда возможно (например, вы можете застрять в структуре, которая допускает только одно регулярное выражение для проверки).

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


a Вы либо получите одно из этих огромных регулярных выражений, либо одно регулярное выражение, содержащее шестнадцать возможностей упорядочения, разделенных |.

Ни один из них, вероятно, не будет столь же эффективным или читаемым, как простой сегмент кода.

3 голосов
/ 26 мая 2011

Во-первых, вот перевод кода Paxdiablo на C #:

public bool Validate(string input)
{
    if (input == null || input.Length < 8)
        return false;
    int counter = 0;
    if (input.Any(Char.IsLower)) counter++;
    if (input.Any(Char.IsUpper)) counter++;
    if (input.Any(Char.IsDigit)) counter++;
    if (input.Any(c => Char.IsPunctuation(c) || Char.IsSymbol(c))) counter++;
    return counter >= 3;
}

Если вы настаиваете на регулярном выражении, вы можете использовать шаблон, аналогичный шаблону Fun с .NET Regex Balancing Groups :

^
(?=.*[a-z](?<Counter>))?
(?=.*[A-Z](?<Counter>))?
(?=.*[0-9](?<Counter>))?
(?=.*[^a-zA-Z0-9](?<Counter>))?
(?<-Counter>){3}   # check we've had at least 3 groups
.{8}

Вы также можете разрешить классы Unicode :

^
(?=.*\p{Ll}(?<Counter>))?
(?=.*\p{Lu}(?<Counter>))?
(?=.*\p{Nd}(?<Counter>))?
(?=.*[\p{S}\p{P}](?<Counter>))?
(?<-Counter>){3}
.{8}
2 голосов
/ 26 мая 2011

Расширенная версия регулярного выражения для PCRE:

/^(?:
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  )
  \S{8,}              # at least 8 non-spaces
$/x
1 голос
/ 26 мая 2011

Комбинаторика не так уж и плоха - есть только четыре способа выбрать три из четырех возможностей; вы можете проверить их с помощью lookaheads в начале регулярного выражения, а затем проверить наличие восьми символов с фактическим соответствием:

^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*\d)|(?=.*[A-Z])(?=.*[a-z])(?=.*[_\W])|(?=.*[A-Z])(?=.*\d)(?=.*[_\W])|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}

(Привязка предназначена для повышения эффективности при сбое, без него она будет работать).

Вероятно, пароль не имеет значения, но приведенная выше версия потенциально может просмотреть всю строку более одного раза для одного и того же типа символа, особенно при сбое. Вы можете выделить это следующим образом за счет читабельности:

^(?:(?=.*[A-Z])(?:(?=.*[a-z])(?:(?=.*\d)|(?=.*[_\W]))|(?=.*\d)(?=.*[_\W]))|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}
0 голосов
/ 21 июня 2011

Правильный ответ на мой вопрос:

регулярное выражение:

^ ((? =. [\ D]) (? =. [Az]) (? =. [AZ]) |?.?.? (= [AZ]) (= [AZ]) (= [^ \ ш \ д \ с]) |.?.?. (= [\ d]) (= [AZ])(? = [^ \ ш \ д \ с].) |. (?. = [\ d]) (?. = [AZ]) (?. = [^ \ ш \ д \ с])) {8, 30} $

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...