Mad*_*ner 16 c++ regex gcc clang c++14
我正在解析stackoverflow转储,并在这个看似无辜的问题上提出了一个小的,几乎看不见的细节,它在文本的末尾有22311个空格.
我正在使用std :: regex(不知何故,它们对我来说比boost :: regex更好)用单个空格替换所有连续的空格,如下所示:
std::regex space_regex("\\s+", std::regex::optimize);
...
std::regex_replace(out, in, in + strlen(in), space_regex, " ");
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
for(gcc 5.3.0)
$ g++ -O3 -std=c++14 regex-test.cpp -o regex-test.out
Run Code Online (Sandbox Code Playgroud)
NSIGSEGV出现之前的最大值是21818(对于这个特定的字符串),以及
$ g++ -O0 -std=c++14 regex-test.cpp -o regex-test.out
Run Code Online (Sandbox Code Playgroud)
这是12180.
"好吧,让我们尝试铿锵,这是趋势,旨在取代gcc" - 从来没有我错了.随着-O0clang(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
Run Code Online (Sandbox Code Playgroud)
问题1:这是一个错误吗?如果是的话,我应该报告吗?
问题2:是否有智能方法来克服这个问题(除了增加系统堆栈大小,尝试其他正则表达式库并编写自己的函数来替换空格)?
修订: 为libstdc ++创建的错误报告
是的,这是一个错误.
cout << '"' << regex_replace("Small text\n\nwith several\n\nlines." + string(22311, ' '), regex("\\s+", regex::optimize), " ") << '"' << endl;
Run Code Online (Sandbox Code Playgroud)
但这只是一个针对libstdc ++的错误,所以请随时在此报告:https://gcc.gnu.org/bugzilla/buglist.cgi?product = gcc&component = libstdc%2B%2B&resolution = ---
如果你要求一个新的regex工作,我已经尝试了一些不同的版本,并且所有这些版本都在libstdc ++上失败,所以我想说,如果你想用a regex来解决这个问题,你需要针对libc ++进行编译.
但老实说,如果你使用regex剥离复制空格,"现在你有两个问题"
一个更好的解决方案可以使用adjacent_find它运行正常使用的libstdc ++以及:
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); }));
}
Run Code Online (Sandbox Code Playgroud)
这将返回你regex想要的相同的东西:
"有几行的小文字."
但如果你想要简单,你也可以使用unique:
test.resize(distance(test.begin(), unique(test.begin(), test.end(), [](const auto& a, const auto& b) { return isspace(a) && isspace(b); })));
Run Code Online (Sandbox Code Playgroud)
哪个将返回:
"
有几
行的小文字."