2016-05-18 179 views
4

我试图执行下列基于C++ STL代码在一个比较大的SQL脚本替换文本(〜8MB):堆栈溢出:: regex_replace

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更新5

编辑2:原始文件是超过23000行。我将文件减少到3,500行并仍然出现错误。当我用另一条〜50条线将它裁减到3,456条线时,错误消失了。如果我只将这些剪切线放入文件中,错误仍然消失。这表明这个错误与特定的文本无关,而只是太多而已。

编辑3:工作例子证明经营得当这里: https://regex101.com/r/iD1zY6/1 它不会在STL代码工作,虽然。

+0

您知道触发堆栈溢出的'strInput'吗? – vu1p3n0x

+0

@ vu1p3n0x是的,但我不知道如何分享如此大的输入字符串。我不想在问题中提供8 MB的文本。 – BlueMonkMN

+0

你的正则表达式是以行('“^ ... $”')为界的吗?文件是否都是一行?或者是否有一行触发它?还是只在一次处理整个文件时触发它? – vu1p3n0x

回答

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; 
+0

很高兴您让它工作:) –

2

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

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

修改:

  • 直列锚删除:你明确测试的换行符
  • 为DB对象关键字重复操作删除 - 在这一点上重复会使原来的脚本语法无效。通过单词边界替换
  • 初始空白模式(注意双反斜线 - 转义序列是正则表达式引擎,而不是编译器)

如果你可以肯定的是...

  • create ...言论并在字符串中没有出现,并且

  • 你不需要create ...发言,然后是一个go或不区分(例如:因为所有的语句用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); 

Here是后一种方法演示 - 减少步骤稍微超过1/4)。

+0

开头的“\ b”似乎阻止了STL正则表达式出于某种原因在一行的开头匹配“create”。需要双倍\\我假设。 – BlueMonkMN

+0

看来这个解决方案仍然会太慢。如果我正在编写C#代码,我会将它拆分为“\ ngo \ n”并替换每个组件。但我不知道如何在STL中做到这一点。它已经运行了一分多钟,但仍然没有完成,我认为VB6能够在不到一分钟的时间内通过一次处理一行来完成这项工作(我正在重写一些旧代码)。我认为我可以通过一次处理所有代码来简化代码,但代价太高。我甚至不知道如何将文本拆分为符合STL的行。 – BlueMonkMN

+0

所以也许分裂建议在[这个SO回答](http://stackoverflow.com/a/13172514)会有帮助吗?要替换的文本部分不会显示为跨越行。 – collapsar