【问题标题】:std::regex - lookahead assertion not always workingstd::regex - 前瞻断言并不总是有效
【发布时间】:2021-06-11 09:35:22
【问题描述】:

我正在编写一个模块,它将一些字符串替换为文本以提供给脚本语言。该语言的语法是模糊的 lisp-y,因此表达式由括号和由空格分隔的符号限定,其中大多数以“$”开头。像这样的正则表达式似乎应该在适当的符号边界处匹配:

auto re_match_abc = std::regex{ "(?=.*[[:space:]()])\\$abc(?=[()[:space:]].*)" };

但在我的环境中(Visual C++ 2017, 15.9.19, target C++-17)它可以匹配前面没有合适边界的字符串:

std::cout << "  $abc   -> " << std::regex_replace(" $abc ", re_match_abc, "***") << std::endl;
std::cout << " ($abc)  -> " << std::regex_replace("($abc)", re_match_abc, "***") << std::endl;
std::cout << "xyz$abc  -> " << std::regex_replace("xyz$abc ", re_match_abc, "***") << std::endl;
std::cout << " $abcdef -> " << std::regex_replace(" $abcdef", re_match_abc, "***") << std::endl;

// Result from VC++ 2017:
//
//       $abc   ->  ***
//      ($abc)  -> (***)
//     xyz$abc  -> xyz***     <= What's going wrong here?
//      $abcdef ->  $abcdef

为什么该正则表达式忽略了在匹配文本前至少有一个空格或括号的正向预测要求?

[我意识到还有其他方法可以完成这项工作并且做得非常稳健也许我应该使用一些东西将字符串转换为令牌流,但是对于我的直接工作(并且因为创作字符串的人得到处理的就在我旁边,所以我们可以协调)我认为现在可以使用正则表达式替换。]

【问题讨论】:

    标签: c++ regex regex-lookarounds


    【解决方案1】:

    您需要改为使用积极的后视。你真正想要的是:

    auto re_match_abc = std::regex{ "(?<=[[:space:]()])\\$abc(?=[()[:space:]])" };
    

    您可以在https://regex101.com/ 之类的网站上试用它(只需删除 C++ 字符串所需的转义反斜杠)。它解释了正则表达式的每一部分正在做什么,并向您展示所有匹配的内容。

    请记住,这也将匹配 )$abc) 之类的内容

    编辑:std::regex 显然不支持后视。对于你的具体情况,你可以尝试这样的事情:

        auto re_match_abc = std::regex{ "([[:space:]()])\\$abc(?=[()[:space:]])" };
        std::cout << "  $abc   -> " << std::regex_replace(" $abc ", re_match_abc, "$1***") << std::endl;
        std::cout << " ($abc)  -> " << std::regex_replace("($abc)", re_match_abc, "$1***") << std::endl;
        std::cout << "xyz$abc  -> " << std::regex_replace("xyz$abc ", re_match_abc, "$1***") << std::endl;
        std::cout << " $abcdef -> " << std::regex_replace(" $abcdef", re_match_abc, "$1***") << std::endl;
    

    输出:

      $abc   ->  *** 
     ($abc)  -> (***)
    xyz$abc  -> xyz$abc 
     $abcdef ->  $abcdef
    

    try it here

    在这里,我们有一个普通的捕获组,而不是后视。在替换中,我们发出我们捕获的任何内容(括号或空格),然后是我们想要替换 $abc 的实际字符串。

    【讨论】:

    猜你喜欢
    • 2023-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多