Регулярные выражения не убивают процессоры, авторы регулярных выражений делают. ;)
А если серьезно, если бы регулярные выражения всегда выполнялись так медленно, как вы описали, никто бы их не использовал. Прежде чем вы начнете загружать серебряные пули, такие как опция Compiled
, вы должны вернуться к своему регулярному выражению и посмотреть, можно ли его улучшить.
И это возможно. Каждое ключевое слово находится в своей собственной ветке / альтернативе, и каждая ветвь начинается с .*
, поэтому первое, что делает каждая ветвь, - это поглощает оставшуюся часть текущего абзаца (т. Е. Все до следующей новой строки). Затем он начинает возвращаться, пытаясь сопоставить ключевое слово. Если он возвращается к позиции, с которой он начал, следующая ветвь вступает во владение и делает то же самое.
Когда все ветви сообщили об отказе, двигатель регулярного выражения перемещается вперед на одну позицию и снова проходит через все ветви. Это более десятка веток, умноженное на количество символов в абзаце, умноженное на количество абзацев ... Я думаю, вы поняли. Сравните это с этим регулярным выражением:
Regex re = new Regex(@"^.*?(\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*|keyword1|keyword2|keyword3|keyword4|keyword5|keyword6|keyword7|keyword8|count:(\n\n?[0-9]?)?|keyword10|summary: \n).*$",
RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
Есть три основных изменения:
- Я учел ведущие и конечные
.*
- Я сменил ведущий на
.*?
, сделав его нежадным
- Я добавил якоря начала и конца строки (
^
и $
в режиме Multiline
)
Теперь он делает только одну попытку сопоставления для каждого абзаца (успешно или неудачно) и практически никогда не возвращается. Я мог бы сделать это еще эффективнее, если бы знал больше о ваших данных. Например, если каждое ключевое слово / токен / что-либо начинается с буквы, граница слова будет иметь заметный эффект (например, ^.*?\b(\w+...
).
Опция ExplicitCapture
заставляет все «голые» группы ((...)
) действовать как группы без захвата ((?:...)
), еще больше уменьшая накладные расходы без добавления беспорядка в регулярное выражение. Если вы хотите захватить токен, просто измените эту первую группу на именованную группу (например, (?<token>\w+...
).