Std:: regex, чтобы соответствовать началу/концу строки

В регулярных выражениях JS символы ^ и $ обозначают начало и конец строки. И только с модификатором /m (многострочный режим) они соответствуют началу и концу строки - позиции до и после CR/LF.

Но в std:: regex/символы режима ECMAscript ^ и $ всегда соответствуют началу и концу строки.

Есть ли способ в std:: regex определить начало и конец строки совпадений? Другими словами: поддержка многострочного режима JavaScript...

Ответ 1

По умолчанию режим ECMAscript уже обрабатывает ^ как начало ввода и начало строки, а $ - как конец ввода и конец строки. Невозможно сделать так, чтобы они соответствовали только началу или концу ввода, но можно сделать так, чтобы они соответствовали только началу или концу строки:

При вызове std::regex_match, std::regex_search или std::regex_replace существует аргумент типа std::regex_constants::match_flag_type, который по умолчанию на std::regex_constants::match_default.

  • Чтобы указать, что ^ соответствует только началу строки, укажите std::regex_constants::match_not_bol
  • Чтобы указать, что $ соответствует только концу строки, укажите std::regex_constants::match_not_eol
  • Поскольку эти значения являются битовыми флагами, для определения обоих просто поразрядно - или их вместе (std::regex_constants::match_not_bol | std::regex_constants::match_not_eol)
  • Обратите внимание, что начало ввода может подразумеваться без использования ^ и независимо от наличия std::regex_constants::match_not_bol путем указания std::regex_constants::match_continuous

Это хорошо объясняется в документации по грамматике ECMAScript на cppreference.com, которую я настоятельно рекомендую использовать в целом над cplusplus.com.

Предостережение: я тестировал MSVC, Clang + libc++ и Clang + libstdc++, и только MSVC в настоящее время ведет себя корректно.

Ответ 2

TL; DR

  • MSVC: ^ и $ уже соответствуют началу и концу строк
  • C++ 17: использовать std::regex_constants::multiline параметр
  • Другие компиляторы сопоставляют только начало строки с ^ и конец строки с $ без возможности переопределить их поведение.

Во всех реализациях std::regex, кроме MSVC и до C++ 17, ^ и $ соответствуют началу и концу строки, а не строке. Смотрите это демо, которое не находит соответствия в "1\n2\n3" с ^\d+$ регулярным выражением. Когда вы добавляете варианты (см. ниже), есть 3 совпадения.

Однако в MSVC и C++ 17 ^ и $ могут совпадать с началом/концом строки.

C++ 17

Используйте параметр std::regex_constants::multiline.

Компилятор MSVC

В проекте C++ в Visual Studio следующее

std::regex r("^\\d+$");
std::string st("1\n2\n3");
for (std::sregex_iterator i = std::sregex_iterator(st.begin(), st.end(), r);
    i != std::sregex_iterator();
    ++i)
{
    std::smatch m = *i;
    std::cout << "Match value: " << m.str() << " at Position " << m.position() << '\n';
}

выведет

Match value: 1 at Position 0
Match value: 2 at Position 2
Match value: 3 at Position 4

Временные решения, которые работают в компиляторах C++

В std::regex нет универсальной опции, чтобы якоря соответствовали началу/концу строки для всех компиляторов. Вам нужно подражать с чередованием:

^ -> (^|\n)
$ -> (?=\n|$)

Обратите внимание, что $ можно полностью "эмулировать" с помощью (?=\n|$) (где вы можете добавить больше символов-разделителей строк или последовательностей символов, например (?=\r?\n|\r|$)), но с помощью ^ вы не сможете найти 100% обходной путь.

Поскольку поддержки "lookbehind" нет, вам, возможно, придется настраивать другие части шаблона регулярных выражений, поскольку (^|\n) нравится использовать захват групп чаще, чем с поддержкой "lookbehind".

Ответ 3

Следующий фрагмент кода соответствует адресам электронной почты, начинающимся с [az], за которым следуют 0 или 1 точка, затем 0 или более букв az и заканчивающихся на "@gmail.com". Я проверял это.

string reg = "^[a-z]+\\.*[a-z]*@gmail\\.com$";

regex reg1(reg, regex_constants::icase);
reg1(regex_str, regex_constants::icase);
string email;
cin>>email;
if (regex_search(email, reg1))

Ответ 4

Вы можете эмулировать Perl/Python/PCRE \A, который соответствует в начале строки, но не после новой строки, с помощью регулярного выражения Javascript ^(?<!(.|\n)]), что переводится на английский как "соответствует началу" строки, которая не имеет предшествующего символа ".

Вы можете эмулировать Perl/Python/PCRE \z, который соответствует только в конце строки, используя (?!(.|\n))$. Чтобы получить эффект \Z, который соответствует только в конце строки, но допускает одиночный перевод строки непосредственно перед этим концом строки, просто добавьте необязательный перевод строки: \n?(?!(.|\n))$.