Страницы

Поиск по вопросам

понедельник, 13 апреля 2020 г.

boost::regex и pcre исключение Ran out of stack space trying to match the regular expression

#cpp #регулярные_выражения #boost #pcre

                    
Когда то давно задавал подобный вопрос на другом форуме, но никто внятно не ответил.
Есть две библиотеки для работы с регулярными выражениями по стандарту PCRE.
Это boost::regex (или урезанный вариант std::regex) и библиотека PCRE.
Собственно есть сложное регулярное выражение.
там присутствуют подобные выражения
"+string_open+"(?>(?>(?!"+string_open+"|"+string_close+").)+|(?R))*"+string_close+"

Всё это дело замечательно отрабатывает для небольших входящих строк. но когда входящая
строка превышает допустим 1000 символов и условия указанные в регулярном выражении
выполняются, то выбрасывается исключение и в boost и в pcre.
Ran out of stack space trying to match the regular expression.
Собственно здесь говорится что происходит выход за пределы некоего стека.
1) Библиотеку pcre можно собрать из исходников, и увеличить там некоторые константы
#define , точно не помню что именно там было, то ли указание на использование рекурсивной
модели работы то ли еще что то.
Но в общем скомпилированная таким образом библиотека pcre стала работать с неограниченными
по объему строками и решала поставленную задачу. Сейчас используется именно такая модель.
Однако данный метод увеличил время работы регулярных выражений в 10-20 раз. 
раньше программа поднималась за 4 секунды, а с использованием такого подхода 40-50
секунд.
2) В boost ни где не смог найти информацию, о том как и где изменять значения этого
стека. 
Что из себя представляет этот стек? Этот тип формируют сами библиотеки?
Невозможность изменить этот стек, выглядит нелогичным, потому что 
программа нормально отрабатывается для строки допустим 990 символов.
Время выполнения разбора 5 миллисекунд. Занимаемая память 400 кб.
Добавляются 20 символов и всё ran out stack.    


Ответы

Ответ 1



Это читали? Что бы сделал я? Попробовал обе опции: и BOOST_REGEX_RECURSIVE, и BOOST_REGEX_NON_RECURSIVE; Увеличил бы BOOST_REGEX_BLOCKSIZE и BOOST_REGEX_MAX_BLOCKS.

Ответ 2



Для такой задачи лучше использовать более серьёзный парсер, нежели регулярные выражения. Например, boost::spirit. Обе проблемы — стека и быстродействия — решаются сами собой. Из "недостатков" могу отметить большее время компиляции (порядка десятков секунд, частично решаемо с помошью прекомпилированных хэдеров) и достаточно крутая в начале кривая обучения (там активно используются ленивые вычисления, к логике которых надо привыкнуть — но дальше всё проще).

Комментариев нет:

Отправить комментарий