Улучшить производительность регулярного выражения - PullRequest
3 голосов
/ 07 июля 2010

Мое программное обеспечение позволяет пользователям использовать регулярные выражения для подготовки файлов. Я нахожусь в процессе добавления библиотеки регулярных выражений по умолчанию с общими выражениями, которые можно повторно использовать для подготовки различных форматов. Одна общая задача - удалить crlf в определенных частях файлов, но не в других. Например, это:

    <TU>Lorem 
    Ipsum</TU>
    <SOURCE>This is a sentence
    that should not contain
    any line break.
    </SOURCE>

Должно стать:

    <TU>Lorem 
    Ipsum</TU>
    <SOURCE>This is a sentence that should not contain any line break.
    </SOURCE>

У меня есть рексеп, который отлично справляется со своей работой:

(?(?<=<SOURCE>(?:(?!</?SOURCE>).)*)(\r\n))

Проблема в том, что он интенсивно обрабатывает файлы размером более 500 КБ, это может занять более 30 секунд. (регулярное выражение компилируется, в этом случае некомпилированное выполняется намного медленнее)

Это не большая проблема, но мне интересно, есть ли лучший способ достичь тех же результатов с Regex.

Заранее спасибо за ваши предложения.

Ответы [ 3 ]

2 голосов
/ 07 июля 2010

Я бы добавил к регулярному выражению отрицательное предпросмотр, чтобы убедиться, что вы действительно можете сопоставить \r\n в текущей позиции.В противном случае движок должен выполнить весь просмотр назад (произвольный размер для загрузки) для каждого отдельного символа во всем файле, только чтобы выяснить, что возврат каретки не подлежит замене.

(?=\r\n)(?(?<=<SOURCE>(?:(?!</?SOURCE>).)*)(\r\n))

должно быть намного быстрее.По крайней мере, в RegexBuddy движку regex требуется намного меньше шагов для завершения матча.Если этого не происходит в .NET, я не знаю почему.Возможно, условное регулярное выражение не так эффективно (я должен признать, что сначала я его не распознал и подумал, что в вашем регулярном выражении есть синтаксическая ошибка).Я думаю, что вам не нужно условное регулярное выражение в этом сценарии.Как насчет

\r\n(?<=<SOURCE>(?:(?!</?SOURCE>).)*)

Это быстрее?Я предполагаю, что вы используете RegexOptions.Singleline для компиляции регулярного выражения.

Если нет, то, вероятно, очень много возвратов каретки и много других символов внутри ваших блоков <SOURCE>, а также произвольныйРазмер смотреть назад просто занимает много времени.Тогда мое другое предложение состоит в том, чтобы разделить задачу:

  1. Соответствует блоку <SOURCE>
  2. Заменить все CRLF внутри блока (не требуется регулярное выражение)
  3. Заменить<SOURCE> блок
2 голосов
/ 07 июля 2010

Попробуйте это:

\r\n(?=(?>[^<>]*(?><(?!/?SOURCE>)[^<>]*)*)</SOURCE>)

Он начинается с совпадения \r\n, а затем использует прогноз, чтобы увидеть, находится ли совпадение между <SOURCE> и </SOURCE>. Он делает это, ища </SOURCE>, но если он сначала находит <SOURCE>, он терпит неудачу. Атомарные группы препятствуют сохранению информации о состоянии, которая понадобится для возврата, потому что проходить или не проходить, возврат никогда не требуется.

2 голосов
/ 07 июля 2010

«Компиляция» регулярного выражения просто означает преобразование его из детерминированного конечного автомата в недетерминированный конечный автомат .Это не «компиляция в машинный код», как вы могли бы ожидать.

NFA, как правило, меньше, чем их соответствующий DFA, и могут эффективно выполнять больше space .Каждый DFA имеет по крайней мере один эквивалентный NFA и наоборот.Однако регулярные выражения, совместимые с Perl , на самом деле не являются регулярными .Так что я не знаю, что они конвертируются в NFA или если «компилировать» просто еще одну форму лексического анализа, которую когда-то делали, больше не нужно делать.

PCRE медленны в соответствии с Russ Cox , частично из-за их нерегулярности, и ваше выражение выше весьма нерегулярно.

О, и если выпытаясь распознать вложенные теги с помощью регулярных выражений, не надо.Используйте настоящий (X|HT)?ML парсер.Вы действительно не хотите, чтобы пони пришли

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...