问题 std :: regex,匹配字符串的开头/结尾


在JS正则表达式符号中 ^ 和 $ 指定 字符串的开头和结尾。而且只有 /m 他们匹配的修饰符(多行模式) 开始和结束  - CR / LF前后的位置。

但在 的std ::正则表达式/ ECMAscript模式符号 ^ 和 $ 比赛 开始和结束 总是。

在std :: regex中有什么方法可以定义 字符串的开头和结尾 赛点?换句话说:支持JavaScript多线模式......


6714
2017-09-22 17:46


起源

关键在于 ^ 和 $ 匹配字符串的开头和结尾。看到 ideone.com/amatBf 和 ideone.com/0D7eS7 - Wiktor Stribiżew
@WiktorStribiżew好的,如何修改样品 ^ 和 $ 匹配开始/结束线? - c-smile
我已经提到:对于行尾,它是 (?=\n|$),对于行的开头,它只能是一种消费模式 (^|\n)。我知道,这非常不舒服。如果您真的需要多线行为,切换到Boost正则表达式可能会成为最佳选择 ^ / $。 - Wiktor Stribiżew


答案:


默认情况下,ECMAscript模式已经处理 ^ 作为两个输入的开始  开头的,和 $ 作为两个输入结束  行结束。没有办法使它们匹配 只要 输入的开头或结尾,但可以使它们匹配 只要 开头或结尾:

调用时 std::regex_matchstd::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具有正确的行为。


6
2017-09-22 17:53



来自您的链接cppreference.com断言^(行首)匹配1)紧跟LineTerminator字符的位置。 (如果支持,请参阅LWG issue 2343)2)输入的开头(除非std :: regex_constants :: match_not_bol(仅限C ++)已启用)这与所需的完全不同。我需要 ^ 只匹配“输入的开头”而没有别的。 - c-smile
@ c-smile:非常正确,我误解了它。答案已更新。 - ildjarn
我的心理解析器无法解析:“要指定$仅匹配行尾,请指定std :: regex_constants :: match_不_eol“至于我 match_not_eol 意思是完全相反的事情:如果设置了那个标志那么它不应该与EOL匹配,只是输入的结束,对吗?这真的很有道理。在你解释它的方式,该标志是无用的。 - c-smile
@ c-smile:这意味着“不要善待 first 作为BOL或 last 作为EOL“, 不 你想要什么。我出于某种原因链接到文档。 ; - ] - ildjarn
不清楚这里的“第一”和“最后”是什么意思。无论如何,问题是:用什么标志 ^ 仅匹配输入的开头(与...相同) $ 和输入结束)?在提升中有明确的 \A 和 \z  显式匹配输入的head / tail的标记:boost.org/doc/libs/1_31_0/libs/regex/doc/syntax.html   好像std失去了这个功能。 - c-smile


^ 和 $ 匹配开头和结尾 ,不是一条线。看到 这个演示 没有找到任何匹配 "1\n2\n3" 同 ^\d+$ 正则表达式。添加替换时(见下文), 有3场比赛

没有选择 std::regex 使锚点匹配线的开始/结束。您需要使用替换来模拟它:

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

注意 $ 可以完全“模仿” (?=\n|$) (您可以在其中添加更多行终止符号或符号序列,例如 (?=\r?\n|\r|$)),但有 ^,你找不到100%的解决方法。

由于没有lookbehind支持,您可能必须调整正则表达式模式的其他部分,因为 (^|\n) 喜欢使用捕获组比使用lookbehind支持更频繁。


4
2017-09-22 17:54



我认为我的措辞有点忙乱,但我所推动的是你的初步假设是错误的。该 ^ 只匹配字符串的开头,和 $ 只匹配字符串的结尾。 - Wiktor Stribiżew
“断言^(行首)匹配紧跟LineTerminator字符的位置....” en.cppreference.com/w/cpp/regex/ecmascript - c-smile
@ c-smile:我知道你的意思,但我的答案是基于实践经验。 - Wiktor Stribiżew


以下代码段匹配以[a-z]开头,后跟0或1点,然后是0或更多a-z字母,然后以“@ 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))

0
2018-05-10 03:08