C++ - 在长时间的多行匹配期间,STD 正则表达式在 MSVC 中崩溃
C++ - STD regex crashes in MSVC during long multiline match
我正在尝试使用 std::regex 从源文件中提取/* ... */
样式的注释。但是"regex_search"有时会在跨越多行的长匹配中崩溃(未经处理的异常(。
性病示例(不起作用(
此示例为我崩溃:
#include <iostream>
#include <regex>
int main()
{
std::string in = "/*naaanaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaanaaaaaaaaan*/";
std::regex e(".*/\*(n|.)*?\*/");
std::smatch m;
while (std::regex_search(in, m, e))
{
std::cout << m[0].str() << std::endl;
in = m.suffix();
}
return 0;
}
我正在使用Visual Studio 2013,所以这可能是编译器特定的问题。
编辑:正如@T.C.在注释中指出的那样,该代码在GCC 4.9下工作,并且会引发堆栈溢出异常。这可能只是Visual C++编译器的问题,也可能只是GCC分配了更大的堆栈。
Qt示例(工作(
我尝试在Qt中实现同样的事情没有问题,所以我认为我没有犯任何错误。但我非常希望不依赖任何外部库。
QRegularExpression re(".*/\*(n|.)*?\*/");
QRegularExpressionMatchIterator it = re.globalMatch(QString(in.c_str()));
while (it.hasNext())
{
QRegularExpressionMatch match = it.next();
QString word = match.captured(0);
}
问题
这可能是 std::regex 实现中的错误吗?我在任何地方犯了错误吗?
我认为这不是编译器问题(如果您不使用 gcc <4.9(。正则表达式崩溃,因为获取结果的步骤量太高。尝试对此模式执行相同的操作:
/\*[\s\S]*?\*/
或者用这个模拟所有格量词:
/\*(?=((?:[^*]+|\*(?!/))*))\1\*/
(这两种模式旨在与 ECMAScript 模式配合使用,也就是说,如果我没记错的话,就是正则表达式引擎的默认模式(
关于您的原始模式:
第一个错误是以 .*
开始您的模式(由于您使用 regex_search
方法,因此不需要这样做(。由于量词默认是贪婪的,因此第一个子模式将匹配所有字符,直到每行末尾。在获得匹配项之后,正则表达式引擎需要逐个字符回溯,直到它在字符串中找到/*
(请注意,如果同一行中有多个/*
,则只会找到最后一个(。
第二个错误是使用类似(\n|.)*?
的东西来描述所有字符,直到接下来的内容(即 */
(。
使用这种构造有几个成本:
- 使用捕获组,因此需要支付每个字符的存储成本(逐个(。
- 您支付了更改的成本,因为大多数时候
.
会匹配并且\n
没有任何测试(但是,这取决于您的评论的外观,但编写(?:.|\n)*?
可能会更有性能。 - 最重要的成本可能是您使用具有非贪婪量词的组,因为它强制所有字符的正则表达式引擎进入组并为每个字符离开组。如果没有惰性量词,在某些正则表达式引擎中,
(?:a)+
可能会比a+
慢 150 倍
关于你在评论中提出的问题,我会给你一个大致的答案。
是的,步骤或回溯步骤的数量在某处受到限制。如果正则表达式引擎足够智能,它可能会在预分析期间检测到模式会导致太多工作,然后再尝试做某事,但情况并非总是如此。
要确切地知道发生了什么,您可以将正则表达式模式放在 try/catch 块中,并检查以下两个错误:
if (e.code() == std::regex_constants::error_complexity)
std::cerr << "The complexity of an attempted match against a regular expression exceeded a pre-set level.n";
else if (e.code() == std::regex_constants::error_stack)
std::cerr << "There was insufficient memory to determine whether the regular expression could match the specified character sequence.n";
呵。我最近在静态分析代码中遇到了同样的问题。所以这是解决方案,尽管它确实依赖于第三方库(我的(:
// http://www.benhanson.net/lexertl.html
#include <lexertl/generator.hpp>
#include <lexertl/iterator.hpp>
int main()
{
std::string in = "/*naaanaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaanaaaaaaaaaaaaaaaaanaaaaaaaaanaaaaaaaaanaaaaaaaaan*/";
lexertl::rules rules;
lexertl::state_machine sm;
rules.push("[/][*](n|.)*?[*][/]", 1);
rules.push(".|n", rules.skip());
lexertl::generator::build(rules, sm);
lexertl::citerator iter(in.c_str(), in.c_str() + in.size(), sm);
lexertl::citerator end;
for (; iter != end; ++iter)
{
std::cout << iter->str() << std::endl;
}
return 0;
}
- 如何使 std::正则表达式匹配 Utf8
- C++11 (MSVS2012) 正则表达式在多行 std::string 中查找文件名
- std::正则表达式捕获组语法错误
- std::正则表达式转义"+"符号
- 使用 STD 正则表达式标记逗号分隔的列表
- 对 std::string 执行正则表达式搜索和替换
- 仅查找第一个 std::正则表达式有效匹配
- 减少 std::正则表达式编译时间 C++
- 将Javascript正则表达式模式转换为C++std::regex的规则
- C++ std::正则表达式多行语法
- std::正则表达式无法按预期工作
- C++ - 在长时间的多行匹配期间,STD 正则表达式在 MSVC 中崩溃
- C++ std::正则表达式 查找多个匹配项
- 使用 std::正则表达式进行简单的 RX 是一种很好的做法
- c++中的STD正则表达式
- 如何使用正则表达式删除std::wstring中特定短语的所有实例
- Microsoft 的 std::正则表达式的实现
- C++ 2011 std::正则表达式根本不起作用
- 将正则表达式存储在变量(std::string)中
- c++ STD正则表达式问号问题