为什么std :: regex_iterator会导致堆栈溢出这个数据?

Ben*_*enj 7 c++ regex c++11

我一直在std::regex_iterator用来解析日志文件.我的程序已经运行了好几个星期并且解析了数百万条日志行,直到今天,今天我在日志文件中运行并且堆栈溢出.事实证明,日志文件中只有一个日志行导致了问题.有谁知道为什么我的正则表达式引起如此大规模的递归?这是一个小的自包含程序,它显示了问题(我的编译器是VC2012):

#include <string>
#include <regex>
#include <iostream>

using namespace std;

std::wstring test = L"L3  T15356 79726859 [CreateRegistryAction] Creating REGISTRY Action:\n"
                L"  Identity: 272A4FE2-A7EE-49B7-ABAF-7C57BEA0E081\n"
                L"  Description: Set Registry Value: \"SortOrder\" in Key HKEY_CURRENT_USER\\Software\\Hummingbird\\PowerDOCS\\Core\\Plugins\\Fusion\\Settings\\DetailColumns\\LONEDOCS1\\Search Unsaved\\$AUTHOR.FULL_NAME;DOCSADM.PEOPLE.SYSTEM_ID\n"
                L"  Operation: 3\n"
                L"  Hive: HKEY_CURRENT_USER\n"
                L"  Key: Software\\Hummingbird\\PowerDOCS\\Core\\Plugins\\Fusion\\Settings\\DetailColumns\\LONEDOCS1\\Search Unsaved\\$AUTHOR.FULL_NAME;DOCSADM.PEOPLE.SYSTEM_ID\n"
                L"  ValueName: SortOrder\n"
                L"  ValueType: REG_DWORD\n"
                L"  ValueData: 0\n"
                L"L4  T15356 79726859 [CEMRegistryValueAction::ClearRevertData] [ENTER]\n";

int wmain(int argc, wchar_t* argv[])
{
    static wregex rgx_log_lines(
        L"^L(\\d+)\\s+"             // Level
        L"T(\\d+)\\s+"              // TID
        L"(\\d+)\\s+"               // Timestamp
        L"\\[((?:\\w|\\:)+)\\]"     // Function name
        L"((?:"                     // Complex pattern
          L"(?!"                    // Stop matching when...
            L"^L\\d"                // New log statement at the beginning of a line
          L")"                      
          L"[^]"                    // Matching all until then
        L")*)"                      // 
        );

    try
    {
        for (std::wsregex_iterator it(test.begin(), test.end(), rgx_log_lines), end; it != end; ++it)
        {
            wcout << (*it)[1] << endl;
            wcout << (*it)[2] << endl;
            wcout << (*it)[3] << endl;
            wcout << (*it)[4] << endl;
            wcout << (*it)[5] << endl;
        }
    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

ric*_*ici 4

对每个角色进行测试的负前瞻模式对我来说似乎是一个坏主意,而且您想要做的事情并不复杂。您想要匹配 (1) 该行的其余部分,然后 (2) 任意数量的以下 (3) 行,这些行以 L\d 以外的内容开头(小错误;见下文):(另一个编辑:这些是正则表达式;如果你想将它们写为字符串文字,则需要更改\\\。)

 .*\n(?:(?:[^L]|L\D).*\n)*
 |   |  |
 +-1 |  +---------------3
     +---------------------2
Run Code Online (Sandbox Code Playgroud)

在 Ecmascript 模式下,.不应匹配 \n,但您始终可以.将该表达式中的两个 s替换为[^\n]

编辑添加:我意识到,如果日志条目末尾之前有一个空行,这可能不起作用,但这应该涵盖这种情况;为了更加精确,我改为.[^\n]

 [^\n]*\n(?:(?:(?:[^L\n]|L\D)[^\n]*)?\n)*
Run Code Online (Sandbox Code Playgroud)