(C++) Определите непревзойденные группы захвата регулярных выражений

Я хочу проверить, соответствует ли пароль следующим требованиям:

Должно:

  • содержать как минимум 1 строчную букву (ASCII 97-122)
  • содержать не менее 1 буквы (65-90)
  • содержать как минимум 1 цифру
  • содержать как минимум 1 специальный символ (33-47, 58-64, 91-96, 123-126)
  • иметь длину от 8 до 20 символов

Следует также сказать мне, что из этих требований не соответствует.


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

regex re("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!-/:-@[-`{-~])(\\S){8,20}$");

Но таким образом я могу только знать, соответствует ли он или нет, так как он возвращает boolean

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

std::string str("AAAaaa111$$$");
std::regex rx("^((?=.*[a-z]).*)((?=.*[A-Z]).*)((?=.*[0-9]).*)((?=.*[!-/:-@[-`{-~]).*)(\\S){8,20}$");
std::match_results< std::string::const_iterator > mr;

std::regex_search(str, mr, rx);

std::cout << "size: " << mr.size() << '\n'; // 6 or 0 only ?
for (int i = 0; i < mr.size(); i++) {
    std::cout << "index: " << i << "\t --> \t" << mr.str(i) << endl;
}

if (regex_match(str, rx)) {
    cout << "tests passed" << endl;
}
else {
    cout << "tests failed" << endl;
}

И это произвело следующий вывод:

size: 6
index: 0         -->    AAAaaa111$$$
index: 1         -->    AA
index: 2         -->    Aa
index: 3         -->
index: 4         -->
index: 5         -->    $
tests passed
Press any key to continue . . .

Чего я хотел бы добиться, так это сказать, какая из групп не смогла сравниться. Например для ввода: SamplePassword1 только 4-я группа не сможет соответствовать, так как она не содержит специального символа. Затем пользователь может быть уведомлен о том, какие конкретные требования не соответствуют паролю. Соответственно, SamplePassword1$ будет иметь матч в каждой из групп и пройти.

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


Здесь я столкнулся с чем-то похожим, но он написан на C# .NET и использует именованные группы захвата.

var re = new Regex("((?<a>a)|(?<b>b))");
var ma = re.Match("a");
Console.WriteLine("a in a: " + ma.Groups["a"].Success); //true
Console.WriteLine("b in a: " + ma.Groups["b"].Success); //false

1 ответ

Решение
std::regex rx("^((?=.*[a-z]))?((?=.*[A-Z]))?((?=.*[0-9]))?((?=.*[!-/:-@[-`{-~]))?(\\S){8,20}$");

и проверить с mr[i].first == str.end(), демонстрация

Тем не менее, вспомнить поговорку:

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

Другие вопросы по тегам