为什么boost regex会耗尽堆栈空间?

时间:2010-12-21 02:08:03

标签: c++ regex boost boost-regex

#include <boost/regex.hpp>
#include <string>
#include <iostream>

using namespace boost;
static const regex regexp(
        "std::vector<"
            "(std::map<"
                   "(std::pair<((\\w+)(::)?)+, (\\w+)>,?)+"
             ">,?)+"
        ">");

std::string errorMsg =
"std::vector<"
        "std::map<"
                "std::pair<Test::Test, int>,"
                "std::pair<Test::Test, int>,"
                "std::pair<Test::Test, int>"
        ">,"
        "std::map<"
                "std::pair<Test::Test, int>,"
                "std::pair<Test::Test, int>,"
                "std::pair<Test::Test, int>"
        ">"
">";
int main()
{
    smatch result;
    if(regex_match(errorMsg, result, regexp))
    {  
        for (unsigned i = 0; i < result.size(); ++i)
        {  
            std::cout << result[i] << std::endl;
        }
    }

//    std::cout << errorMsg << std::endl;

    return 0;
}

这会产生:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error>
>'   what():  Ran out of stack space trying to match the regular expression.

编译
g++ regex.cc -lboost_regex

修改

我的平台:

g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
libboost-regex1.42
Intel(R) Core(TM)2 Quad CPU Q9400 @ 2.66GHz
So the latest Ubuntu 64 bit

2 个答案:

答案 0 :(得分:13)

((\\w+)(::)?)+是所谓的“病态”正则表达式之一 - 它将采用指数时间,因为你有两个表达式,它们彼此依赖于彼此。也就是说,它因catastrophic backtracking而失败。

考虑我们是否遵循链接的示例,并将“更复杂的东西”减少为“x”。让我们用\\w

来做到这一点
  • ((x+)(::)?)+

我们也假设我们的输入永远不会有::。这实际上使正则表达式更复杂,所以如果我们抛弃复杂性,那么我们真的应该让事情更简单,如果没有别的:

  • (x+)+

现在你有一个教科书嵌套量词问题,如上面链接中详述的那样。

有几种方法可以解决这个问题,但最简单的方法可能就是禁止使用atomic group modifier(?>”来回溯内部匹配:

  • ((?>\\w+)(::)?)+

答案 1 :(得分:1)

在本地测试它并且工作正常,我的猜测是你的编译器正在做一些奇怪的事情。

什么版本的gcc?什么平台?哪个版本的提升?

 -> ./regex
std::vector<std::map<std::pair<Test::Test, int>,std::pair<Test::Test, int>,std::pair<Test::Test, int>>,std::map<std::pair<Test::Test, int>,std::pair<Test::Test, int>,std::pair<Test::Test, int>>>
std::map<std::pair<Test::Test, int>,std::pair<Test::Test, int>,std::pair<Test::Test, int>>
std::pair<Test::Test, int>
Test
Test
::
int