std::regex_replace期间堆栈溢出

Stack overflow during std::regex_replace

本文关键字:堆栈 栈溢出 replace regex std      更新时间:2023-10-16

我正在尝试执行以下基于C++STL的代码,以替换相对较大的SQL脚本(~8MB)中的文本:

std::basic_regex<TCHAR> reProc("^[ t]*create[ t]+(view|procedure|proc)+[ t]+(.+)$n((^(?![ t]*go[ t]*).*$n)+)^[ t]*go[ t]*$");
std::basic_string<TCHAR> replace = _T("ALTER $1 $2n$3ngo");
return std::regex_replace(strInput, reProc, replace);

结果是堆栈溢出,很难在这个特定的站点上找到有关该特定错误的信息,因为这也是站点的名称。

编辑:我正在使用Visual Studio 2013 Update 5

编辑2:原始文件超过23000行。我把文件缩减到3500行,仍然得到错误。当我把它再减少大约50行,减少到3456行时,错误就消失了。如果我只把这些剪切线放进文件中,错误仍然没有。这表明错误与特定的文本无关,只是错误太多了

编辑3:完整的工作示例在此处演示了操作是否正确:https://regex101.com/r/iD1zY6/1不过,它在STL代码中不起作用。

以下正则表达式的精简版本根据regex101节省了约20%的处理步骤(请参阅此处)。

\bcreate[ t]+(view|procedure|proc)[ t]+(.+)n(((?![ t]*go[ t]*).*n)+)[ t]*go[ t]*

修改:

  • 删除了内联锚点:您正在明确测试换行符
  • 删除了db对象关键字的repeation运算符-此时的重复将使原始脚本在语法上无效
  • 用单词边界替换的初始空白模式(注意双反斜杠-转义序列用于正则表达式引擎,而不是编译器)

如果你能确定。。。

  • create ...语句不出现在字符串文字和中

  • 您不需要区分后面是否跟有gocreate ...语句(例如,因为所有语句后面都跟有一个go

甚至可以更容易地替换这些字符串:

std::basic_regex<TCHAR> reProc("bcreate[ t]+(view|procedure|proc)");
std::basic_string<TCHAR> replace = _T("ALTER $1");
return std::regex_replace(strInput, reProc, replace);

(下面是后一种方法的演示-将步骤减少到1/4多一点)。

事实证明,与Perl相比,STL正则表达式的性能较差(如果你相信的话,大约慢100倍https://stackoverflow.com/a/37016671/78162),因此,当性能受到严重关注时,显然有必要绝对减少STL/C++中正则表达式的使用。(考虑到我认为C++通常是一种性能更高的语言,C++/STL在这里表现不佳的程度让我大吃一惊)。我最终通过文件流一次读取一行,只在需要处理的行上运行表达式,如下所示:

   std::basic_string<TCHAR> result;
   std::basic_string<TCHAR> line;
   std::basic_regex<TCHAR> reProc(_T("^[ t]*create[ t]+(view|procedure|proc)+[ t]+(.+)$"), std::regex::optimize);
   std::basic_string<TCHAR> replace = _T("ALTER $1 $2");
   do {
      std::getline(input, line);
      int pos = line.find_first_not_of(_T(" t"));
      if ((pos != std::basic_string<TCHAR>::npos) 
          && (_tcsnicmp(line.substr(pos, 6).data(), _T("create"), 6)==0))
         result.append(std::regex_replace(line, reProc, replace));
      else
         result.append(line);
      result.append(_T("n"));
   } while (!input.eof());
   return result;