2016-05-18 2 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); 

В результате переполнения стека , и трудно найти информацию об этой конкретной ошибке на этом конкретном сайте, так как это также имя сайта.

Edit: Я использую Visual Studio 2013 Update 5

Edit 2: Исходный файл составляет более 23 000 строк. Я вырезал файл до 3500 строк и все еще получаю ошибку. Когда я разрезал его еще на 50 строк до 3,456 строк, ошибка исчезнет. Если я вложу только эти строки в файл, ошибка все равно исчезнет. Это говорит о том, что ошибка не связана с конкретным текстом, а просто слишком много.

Edit 3: Полный работает пример демонстрирует работает должным образом здесь: https://regex101.com/r/iD1zY6/1 Это не работает в этом STL кода, хотя.

+0

вы знаете 'strInput', что вызывает переполнение стека? – vu1p3n0x

+0

@ vu1p3n0x Да, но я не уверен, как поделиться такой большой входной строкой. Я не хочу вставлять 8 Мб текста в вопрос. – BlueMonkMN

+0

ваше регулярное выражение ограничено линией (''^... $ "') Является ли файл всей одной строкой? или есть ли одна строка, которая запускает его? или это только при обработке всего файла сразу, что его запускает? – vu1p3n0x

ответ

1

Оказалось, что регулярные выражения STL являются трагическими под-исполнителями по сравнению с Perl (примерно в 100 раз медленнее, если вы можете поверить https://stackoverflow.com/a/37016671/78162), поэтому, по-видимому, необходимо абсолютно свести к минимуму использование регулярных выражений в STL/C++, когда производительность серьезная озабоченность. (Степень, в которой C++/STL работает под управлением, взорвала мой разум, учитывая, что я полагаю, что C++, как правило, является одним из наиболее совершенных языков).Я в конечном итоге передавая поток файла, чтобы прочитать одну строку за один раз и только запустить выражение линий, которые необходимо обрабатывать как это:

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

Следующая сокращенная версия вашего регулярного выражения экономит около 20% шагов обработки в соответствии с regex101 (см. here).

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

Модификация:

  • инлайн якорь удален: вы явно тестирование для перевода строки символов
  • оператор повторения для ключевых слов объектов БД удаляется - повторение в этот момент будет сделать оригинальный сценарий синтаксический неверно ,
  • начальный пробел шаблон заменяется словораздела (обратите внимание на двойную обратную косую черту - последовательность побег для регулярных выражений, а не для компилятора)

Если вы можете быть уверены, что ...

  • в 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 «создавать» в начале строки. Нужна двойная \\ я предполагаю. – BlueMonkMN

+0

Кажется, это решение все еще будет слишком медленным. Если бы я писал код C#, я бы разделил его на «\ ngo \ n» и заменил в каждом компоненте. Но я не знаю, как это сделать в STL. Прошло более минуты и все еще не сделано, и я думаю, что VB6 смог сделать это менее чем за минуту, обработав его по одной строке за раз (я переписываю старый код). Я думал, что могу упростить код, обработав его все сразу, но стоимость оказывается слишком высокой. Я даже не знаю, как разделить текст на строки с STL. – BlueMonkMN

+0

Так что, может быть, расщепление, как было предложено в [this SO answer] (http://stackoverflow.com/a/13172514), поможет? Текстовые части, которые нужно заменить, не отображаются в линиях. – collapsar

Смежные вопросы