Регулярное выражение для строки, которая должна содержать минимум 14 символов, где минимум 2 – числа, а минимум 6 – буквы

Мне нужно регулярное выражение, которое проверяет строку для

  • минимум 14 символов – действительны: A-Za-z0-9#,.-_
  • минимум 6 букв в пределах 14
  • минимум 2 числа в пределах 14

Есть ли способ, которым я могу обернуть это в одном регулярном выражении (в настоящее время у меня есть функция javascript и php, которая выполняет три отдельных теста, один из которых равен 14, другой – по меньшей мере два числа, а другой – не менее 6 букв.

Таким образом, было бы справедливо следующее:

  • blabla2bla2f54a (действительный> 14 всего, с по меньшей мере 6 буквами, как минимум 2 числа)
  • thisIsNotValidAtAll (недопустимо, потому что менее 2 чисел)

Легко! Сначала давайте посмотрим на прокомментированную версию в PHP:

 $re = '/# Match 14+ char password with min 2 digits and 6 letters. ^ # Anchor to start of string. (?=(?:.*?[A-Za-z]){6}) # minimum of 6 letters. (?=(?:.*?[0-9]){2}) # minimum of 2 numbers. [A-Za-z0-9#,.\-_]{14,} # Match minimum of 14 characters. $ # Anchor to end of string. /x'; 

Вот версия JavaScript:

 var re = /^(?=(?:.*?[A-Za-z]){6})(?=(?:.*?[0-9]){2})[A-Za-z0-9#,.\-_]{14,}$/; 

Добавление 20121130:

Я заметил, что этот ответ недавно получил преимущество. Это использует более устаревшее выражение, поэтому я решил, что пришло время обновить его с лучшей …

более эффективное выражение:

Избавляясь от точечной звезды в целом и жадно применяя более точное выражение (отрицательный класс char), получается еще более эффективное решение:

 $re = '/# Match 14+ char password with min 2 digits and 6 letters. ^ # Anchor to start of string. (?=(?:[^A-Za-z]*[A-Za-z]){6}) # minimum of 6 letters. (?=(?:[^0-9]*[0-9]){2}) # minimum of 2 numbers. [A-Za-z0-9#,.\-_]{14,} # Match minimum of 14 characters. $ # Anchor to end of string. /x'; 

Вот новая версия JavaScript:

 var re = /^(?=(?:[^A-Za-z]*[A-Za-z]){6})(?=(?:[^0-9]*[0-9]){2})[A-Za-z0-9#,.\-_]{14,}$/; 

Изменить: Добавлено #,.-_ список допустимых символов.
Изменить: Изменена жадная до ленивой звезды.
Редактировать 20121130: Добавлена ​​альтернативная версия с заменой ленивой точки-звезды более эффективным жадным применением более точного выражения.

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

 $input = 'blabla2bla2f54a'; $errors=array(); if (!preg_match('/^[A-Za-z0-9#,.\-_]*$/', $input)) $errors[] = 'Invalid characters'; if (strlen($input) < 14) $errors[] = 'Not long enough'; if (strlen(preg_replace('/[^0-9]/','',$input)) < 2) $errors[] = 'Not enough numbers'; if (strlen(preg_replace('/[^A-Za-z]/','',$input)) < 6) $errors[] = 'Not enough letters'; if (count($errors) > 0) //Didn't work { echo implode($errors,'<BR/>'); } 
 echo preg_match("/(?=.*[#,.-_])((?=.*\d{2,})(?=.*[a-zA-Z]{6,}).{14,})/", $string); 

Вывод:

 blabla2bla2f54a (1) thisIsNotValidAtAll (0) 

Нет, это невозможно, потому что на самом деле вы хотите сделать три отдельных проверки. Вы не можете их обернуть в одном выражении, которое возвращает true или false. Проблема в том, что у вас есть две равные проверки, которые вам нужно будет комбинировать с помощью оператора AND, и это невозможно. Но мы можем создать суперразмерный RegExp, который распознает все возможные случаи. Но тип типа RegExp в шляпе бессмыслен, потому что это займет много времени, чтобы применить этот тест к вашей строке. Я бы рекомендовал вам выполнить три отдельных теста:

 var result = string.replace(/[A-Za-z]{6}/, "").replace(/[0-9]{2}/, "").replace(/[A-Za-z0-9#,\.\-]{6}/, "").length == 0 ? true : false; // By shortening our sting we're saving time on later chained replacement methods