如何使用超过497个字符wstring的std :: regex_search?

时间:2018-03-07 09:25:47

标签: c++ regex visual-studio

我目前正在开发一个使用正则表达式匹配某些网址的程序。例如,我有这种情况:

int main()
{
    try 
    {
        std::wstring url = L"www.google.com";
        std::wregex reg(L"^(?:(?!math|latex).)*\\.?stackexchange.com");
        std::regex_search(url, reg);
    }
    catch (std::regex_error e)
    {
        std::cout << e.what() << std::endl;
        std::cout << e.code() << std::endl;
    }
}

像魅力一样,在这种情况下它显然不匹配。但是如果我使用超过497个字符的任何url字符串,则regex_search函数将失败。例如:

std::wstring url = L"AAAAA...AAAA"; //498 chars long

e.what()打印:“regex_error(error_stack):内存不足,无法确定正则表达式是否与指定的字符序列匹配。”

e.code()打印:12

令我惊讶的是,堆栈大小似乎是个问题。毕竟,如果您考虑使用正则表达式搜索文件或网站的源代码,那么498个字符就不那么多了。除了将问题推迟到更多(可能是1000个)字符外,有没有办法以可靠的方式解决这个问题?也许用自编写的分配器?虽然我怀疑可以提供在堆上分配堆栈帧的任何形式的分配器。增加堆栈大小并不是一个真正的解决方案,因为它只会延迟问题。

我使用的是Visual Studio Community 2017,版本15.5.6。

这表明我的假设似乎是正确的。

确切异常:RegTest.exe中0x76EECBB2处的未处理异常:Microsoft C ++异常:内存位置为0x00454FF8的std :: regex_error。

1 个答案:

答案 0 :(得分:1)

这里的问题是标准没有指定std::regex_search的实现。

一个好的实现会注意到你的正则表达式最重要的部分是它的下半部分。 stackexchange.com"是一个很好的匹配模式。一旦找到,可以很容易地检查先前的内容。

但是,一个简单的实现将按照它的编写顺序使用你的正则表达式。它将首先匹配^,这当然会在任何输入上立即发生。然后得到(?:(?!math|latex).)*,这是最匹配的模式之一。它不是正式的正则表达式,而是负向前瞻,然后是通配符匹配.,然后重复*

正如评论中所指出的,正则表达式匹配正式贪婪。天真的正则表达式引擎将忽略最终的stackexchange.com部分,并反复尝试匹配(?:(?!math|latex).)*,每次在该部分成功只会导致stackexchange.com失败。

修复方法是自己聪明,并按照您认为最好的顺序进行字符串解析。第一个匹配.stackexchange.com由简单的string::find而不是正则表达式。只有在这种情况下,才能通过regex_search检查子域部分,并使用更简单的表达式。