为什么regex_match抛出“复杂性异常”?

时间:2014-02-13 10:42:56

标签: c++ regex boost-regex

我正在尝试测试(使用boost::regex)文件中的行是否仅包含以空格分隔的数字条目。我遇到了一个我不理解的异常(见下文)。如果有人能够解释为什么抛出它会很棒。也许我在定义模式的方式上做了一些愚蠢的事情?这是代码:

// regex_test.cpp
#include <string>
#include <iostream>
#include <boost/regex.hpp>
using namespace std;
using namespace boost;

int main(){
  // My basic pattern to test for a single numeric expression
  const string numeric_value_pattern = "(?:-|\\+)?[[:d:]]+\\.?[[:d:]]*";
  // pattern for the full line
  const string numeric_sequence_pattern = "([[:s:]]*"+numeric_value_pattern+"[[:s:]]*)+";

  regex r(numeric_sequence_pattern);
  string line= "1 2 3 4.444444444444";
  bool match = regex_match(line, r);
  cout<<match<<endl;

  //...
}

我用

成功编译了
g++ -std=c++11 -L/usr/lib64/ -lboost_regex regex_test.cpp  

由此产生的程序到目前为止工作正常,match == true正如我所希望的那样。但后来我测试了输入行,如

string line= "1 2 3 4.44444444e-16"; 

当然,我的模式不是为了识别格式4.44444444e-16而构建的,我希望match == false。但是,我得到以下运行时错误:

terminate called after throwing an instance of  
'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error> >'  
  what():  The complexity of matching the regular expression exceeded predefined bounds.  
Try refactoring the regular expression to make each choice made by the state machine unambiguous.  
This exception is thrown to prevent "eternal" matches that take an indefinite period time to locate.  

为什么?
注意:我给出的例子是极端的,因为在点工作之后放一个数字就可以了。这意味着

string line= "1 2 3 4.4444444e-16";

只按预期结果match == false。所以,我很困惑。这里发生了什么?

谢谢!


更新:
问题似乎已经解决了。鉴于alejrb的暗示,我将模式重构为

const string numeric_value_pattern = "(?:-|\\+)?[[:d:]]+(?:\\.[[:d:]]*)?";  

这似乎应该有效。不知何故,原始模式\\.内的孤立的可选[[:d:]]+\\.?[[:d:]]*留下了许多以不同方式匹配长序列数字的可能性。
我希望现在的模式是安全的。但是,如果有人找到一种方法将其用于新形式的爆炸,请告诉我!这对我来说不是那么明显是否仍有可能......

1 个答案:

答案 0 :(得分:3)

我会说你的正则表达式可能是指数性的回溯。为了保护你免受循环的影响,如果输入不再是完全不可行的,那么正则表达式引擎就会中止尝试。

经常导致此问题的模式之一是(x+x+)+形式的任何形式 - 当您将第一个模式放在第二个模式中时,您将在此处构建。

http://www.regular-expressions.info/catastrophic.html

进行了很好的讨论