重复的零宽度前瞻

时间:2015-09-22 15:38:16

标签: regex c++11

前几天,我开始考虑如何实现正则表达式引擎,我提出的一个潜在问题涉及零宽度前瞻和重复。例如,当匹配字符串/((?=x))*/上的正则表达式(额外括号以避免无效语法)"xx"时,将尝试尽可能多地匹配内部组。因为,从字符串的开头开始,ZWLA通过,它被认为是匹配,但不消耗任何字符。因此,有人可能会认为正则表达式引擎可能会进入无限循环。

在GNU C ++ 11中测试时,regex_match返回false

regex101上测试时,它会返回匹配。

这种正则表达式构造会被视为“不良形式”吗?或者这种事情是否存在标准行为?

1 个答案:

答案 0 :(得分:1)

  

这种正则表达式构造会被视为“不良形式”吗?或者这种事情是否存在标准行为?

不,((?=x))是有效的正则表达式。它匹配x之前的空字符串。

为什么要匹配空字符串? 在某些情况下,需要匹配空字符串。通常的应用之一是使用某种Regex.Split 拆分

  

有人可能会认为正则表达式引擎可能会进入无限循环。

这确实是一个值得考虑的问题。大多数正则表达式引擎实现都具有自己的多重匹配机制。他们中的大多数在每次检查后将正​​则表达式索引移动到下一个可用位置。在JS中,您需要将gmatch()一起使用,exec()(同样,test()也会这样做)并且引擎将推进lastIndex属性。所有主要语言都将采用类似的方式(C#Regex.Matches,Java while (matcher.find()),Pythons re.finditer/re.findall等)。但是,有时候,必须手动移动索引(这是JS中worksthis one将导致无限循环的示例。

至于为什么你在C ++中没有匹配,很容易解释:regex_match期望整个字符串匹配。如果您使用regex_search,您将获得与空字符串的成功匹配,因为/((?=x))*/正则表达式将匹配第一个x之前的空字符串(如果您不启用多个搜索)。

请参阅this IDEONE demo

string data("xx");
std::regex pattern("((?=x))*");
std::smatch result;

if (regex_search(data, result, pattern)) {
    std::cout << "\"" << result[0].str() << "\"" << std::endl;
}
else 
{
    std::cout << "regex_search failed!" << std::endl;   
}
if (regex_match(data, result, pattern)) {
    std::cout << result[0].str() << std::endl;
}
else
{
    std::cout << "regex_match failed!" << std::endl;    
}

结果:

""
regex_match failed!