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))$
.