我正在解析 stackoverflow 转储并出现 this看似无辜的问题,带有几乎看不见的细节,文本末尾有 22311 个空格。
我正在使用 std::regex (不知何故,它们对我来说比 boost::regex 更好)来用单个空格替换所有连续的空格,如下所示:
std::regex space_regex("\\s+", std::regex::optimize);
...
std::regex_replace(out, in, in + strlen(in), space_regex, " ");
SIGSEGV 出现,我已开始调查。
测试代码:
#include <regex>
...
std::regex r("\\s+", std::regex::optimize);
const char* bomb2 = "Small text\n\nwith several\n\nlines.";
std::string test(bomb2);
for (auto i = 0; i < N; ++i) test += " ";
std::string out = std::regex_replace(test.c_str(), r, " ");
std::cout << out << std::endl;
对于(gcc 5.3.0)
$ g++ -O3 -std=c++14 regex-test.cpp -o regex-test.out
在 SIGSEGV 出现之前的最大 N
是 21818(对于这个特定的字符串),对于
$ g++ -O0 -std=c++14 regex-test.cpp -o regex-test.out
现在是 12180。
'好吧,让我们试试 clang,它很流行,旨在取代 gcc'——我从来没有这么错。使用 -O0
clang (v. 3.7.1) 在 9696 个空间上崩溃 - 少于 gcc,但不多,但使用 -O3
甚至使用 -O2
它在零个空格处崩溃。
故障转储显示大量堆栈跟踪(35k 帧)的递归调用
std::__detail::_Executor<char*, std::allocator<std::__cxx11::sub_match<char*> >, std::__cxx11::regex_traits<char>, true>::_M_dfs
问题 1:这是一个错误吗?如果是,我应该举报吗?
问题 2:有没有聪明的方法来解决这个问题(除了增加系统堆栈大小、尝试其他正则表达式库和编写自己的函数来替换空格)?
修正: bug report为 libstdc++ 创建
最佳答案
这是一个错误吗?如果是,我应该举报吗?
是的,这是一个错误。
cout << '"' << regex_replace("Small text\n\nwith several\n\nlines." + string(22311, ' '), regex("\\s+", regex::optimize), " ") << '"' << endl;
- 使用 libc++ 运行良好:http://coliru.stacked-crooked.com/a/f9ee5438745a5b22
- 在 Visual Studio 2015 上运行良好,您可以通过复制并运行以下位置的代码进行测试:http://webcompiler.cloudapp.net/
- libstdc++ 失败:http://coliru.stacked-crooked.com/a/3f4bbe5c46b6b627
这已在 libstdc++ here 中出现错误.
有解决这个问题的聪明方法吗?
如果你要求一个新的 regex
可以工作,我已经尝试了几个不同的版本,但它们都在 libstdc++ 上失败了,所以我想说,如果你想使用 regex
来解决这个问题,您需要针对 libc++ 进行编译。
但老实说,如果您使用 regex
去除重复的空白,"Now you have two problems"
更好的解决方案可以使用 adjacent_find
其中runs fine with libstdc++ as well :
const auto func = [](const char a, const char b){ return isspace(a) && isspace(b); };
for(auto it = adjacent_find(begin(test), end(test), func); it != end(test); it = adjacent_find(it, end(test), func)) {
*it = ' ';
it = test.erase(next(it), find_if_not(next(it), end(test), [](const auto& i) { return isspace(i); }));
}
这将返回与您的 regex
相同的内容:
"Small text with several lines. "
但如果您为了简单起见,也可以使用 unique
:
test.resize(distance(test.begin(), unique(test.begin(), test.end(), [](const auto& a, const auto& b) { return isspace(a) && isspace(b); })));
哪个会返回:
"Small text
with several
lines. "
关于长序列上的 C++ 正则表达式段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36304204/