在std :: regex_replace期间堆栈溢出

时间:2016-05-18 15:48:24

标签: c++ regex stl

我正在尝试执行以下基于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 $2\n$3\ngo");
return std::regex_replace(strInput, reProc, replace);

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

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

编辑2:原始文件超过23,000行。我将文件减少到3,500行仍然得到错误。当我用另外约50行切割到3,456行时,错误就消失了。如果我只将那些切割线放入文件中,则错误仍然消失。这表明该错误与特定文本无关,但与其过多有关。

编辑3 :完整的工作示例在此处运行正常: https://regex101.com/r/iD1zY6/1 但它在STL代码中不起作用。

2 个答案:

答案 0 :(得分:2)

根据regex101,正则表达式的以下修剪版本可以节省大约20%的处理步骤(参见here)。

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

修改:

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

如果你能确定......

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

  • 您无需区分create ...后跟go的语句(例如,因为所有语句都落后于go

    < / LI>

......替换这些字符串可能更容易:

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);

Here是后一种方法的演示 - 将步骤减少到1/4以上。

答案 1 :(得分:1)

事实证明,STL正则表达式与Perl相比是悲剧性的表现不佳(如果你能相信https://stackoverflow.com/a/37016671/78162,大约慢100倍),所以显然有必要绝对最小化正则表达式的使用。 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;