我正在解析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;
for(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。
'好吧,让我们尝试铿锵,这是趋势,旨在取代gcc' - 从来没有我错了。 -O0
clang(v.3.7.1)在9696个空格处崩溃 - 少于gcc,但不多,但-O3
甚至-O2
,它在ZERO空间崩溃。
崩溃转储呈现出巨大的堆栈跟踪(35k帧)的递归调用
std::__detail::_Executor<char*, std::allocator<std::__cxx11::sub_match<char*> >, std::__cxx11::regex_traits<char>, true>::_M_dfs
问题1 :这是个错误吗?如果是的话,我应该报告吗?
问题2 :是否有智能方法来解决问题(除了增加系统堆栈大小,尝试其他正则表达式库并编写自己的函数来替换空格)?
为libstdc ++创建的修正案 bug report
答案 0 :(得分:8)
是的,这是一个错误。
cout << '"' << regex_replace("Small text\n\nwith several\n\nlines." + string(22311, ' '), regex("\\s+", regex::optimize), " ") << '"' << endl;
但这只是针对libstdc ++的错误,所以请随时在此报告:https://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=libstdc%2B%2B&resolution=---
如果你要求一个有用的新regex
,我尝试了一些不同的版本,并且所有这些版本都在libstdc ++上失败了,所以我想说,如果你想使用{ {1}}要解决这个问题,你需要针对libc ++进行编译。
但老实说,如果您使用regex
去除重复的空格,"Now you have two problems"
更好的解决方案可以使用adjacent_find
:
regex
这将返回您的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); }));
}
会:
“有几行的小文字。”
但如果你想要简单,你也可以使用unique
:
regex
将返回:
“小文字
有几个 线。 “
答案 1 :(得分:0)
问题2(克服问题的聪明方法)
不是很聪明但是......你可以迭代有限的替代品。
一个例子
#include <regex>
#include <iostream>
int main()
{
constexpr int N = 22311;
//std::regex r("\\s+");
std::regex r("\\s{2,100}");
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 = test;
std::size_t preSize;
do
{
preSize = out.size();
out = std::regex_replace(out, r, " ");
}
while ( out.size() < preSize );
std::cout << '\"' << out << '\"' << std::endl;
return 0;
}