我目前正在开发一个使用正则表达式匹配特定 URL 的程序。比如我有这个案例:
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。
最佳答案
这里的问题是标准没有指定 std::regex_search
的实现。
一个好的实现会注意到正则表达式最重要的部分是它的后半部分。 stackexchange.com"
是一个很好的匹配模式。一旦找到,就很容易检查前面是什么。
不过,一个简单的实现将按照编写的顺序使用您的正则表达式。它将首先匹配 ^
,这当然会在任何输入时立即发生。然后它得到一个 (?:(?!math|latex).)*
,这是最难匹配的模式之一。这不是一个正式的正则表达式,而是一个否定的前瞻,后跟通配符匹配 .
,然后重复 *
。
如评论中所述,正则表达式匹配在形式上是贪婪的。天真的正则表达式引擎将忽略最后的 stackexchange.com
部分并反复尝试匹配 (?:(?!math|latex).)*
,每次都成功那部分只会在 stackexchange.com
上失败。
解决方法是你自己要聪明,按照你认为最好的顺序进行字符串解析。首先通过简单的 string::find
匹配 .stackexchange.com
,而不是通过正则表达式。只有在这种情况下,通过 regex_search
检查子域部分,并使用更简单的表达式。
关于c++ - 如何将 std::regex_search 与超过 497 个字符的 wstring 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49148295/