【问题标题】:std::regex infinite loop with gcc 5.4使用 gcc 5.4 的 std::regex 无限循环
【发布时间】:2018-02-10 09:45:11
【问题描述】:

std::regex_match() 未完成(GCC 5.4.0 20160609、x86_64、Ubuntu 16.04)。

但它适用于某些在线编译器:http://cpp.sh/ 可以,例如。

代码尝试将 INI 样式的节标题与可能的“#”-comment 匹配。

#include <regex>

int main(int argc, char *argv[])
{
    std::regex headerPattern("([[:blank:]]*\\[[[:blank:]]*((?:[[:blank:]]*[^[:space:]]+[[:blank:]]*?)+)[[:blank:]]*\\][[:blank:]]*(?:#(?:[^[:space:]]*[[:blank:]]*)*)?)");
    std::smatch headerMatch;
    std::string l("[Hdr 100] # ------------ 22 22 4444 88888888 333");
    return std::regex_match(l, headerMatch, headerPattern) ? 0 : 1;
}

构建:

g++ -std=c++11 main.cpp -o main

代码真的有问题吗?

【问题讨论】:

    标签: regex c++11 gcc


    【解决方案1】:

    该模式会导致灾难性的回溯。发生这种情况是因为您有一个重复的捕获组 ((?:[[:blank:]]*[^[:space:]]+[[:blank:]]*?)+)(为简单起见,让我使用 PCRE 语法将其编写为 ((?:\h*\S+\h*?)+))并且它匹配 0+ 个水平空白,然后是 1 个或多个非空白字符,然后是 0+ 个水平空白,所有这些都用+ 量化。这是一个经典的(a+)+ 案例,其模式使灾难性的回溯不可避免。

    您需要通过以下方式展开此组和其他组:

    std::regex headerPattern("([[:blank:]]*\\[[[:blank:]]*([^[:space:]]+(?:[[:blank:]]+[^[:space:]]+)*)[[:blank:]]*\\][[:blank:]]*(?:#[^[:space:]]*(?:[[:blank:]]+[^[:space:]]+)*)?)");
    

    请参阅regex demo。这里有一个PCRE-converted variant 来理解区别:我上面提到的组现在是\S+(?:\h+\S+)*:1+ 个非空白字符,然后是 0+ 个 1+ 个水平空白字符的序列,然后是 1+ 个非空白字符。最后一个捕获组更改为\S*(?:\h+\S+)*:0+ 个非空白字符,后跟 0+ 个 1+ 个水平空白字符的序列,然后是 1+ 个非空白字符。

    只需将\h 替换为[[:blank:]](或[^\\S\r\n])并将\S 替换为[^[:space:]](或保留它,std::regex 支持它)即可将该 PCRE 模式恢复为您使用的模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多