Pull to refresh

Общие советы по составлению оптимальных регулярных выражений

Reading time3 min
Views2.1K
Регулярные выражения — неотъемлемая часть любого инструмента обработки данных.
Логично, что в различных вариациях поддерживается различный синтаксис и различный функционал.
Не смотря на это принципы работы самих регулярных выражений, машины регулярных выражений и базовые установки оптимизации практически едины.
Где-то на просторах сети видел совершенно глупое заявление, что “регулярные выражения не приспособлены для решения нерегулярных данных” или нечто похожее. Полнейшая ерунда.

Другое дело, что чем более интеллектуален шаблон поиска, тем сильнее машина регулярных выражений “напрягается”, дабы “объяснить” тексту, что от него в итоге требуется.
Кстати, в классической книжке Фридла есть целая глава по оптимизации регулярных выражений. Важная ее часть — сама структура главы. Сначала рассматривается общий принцип оптимизации самих по себе выражений, а далее — оптимизация применительно к языкам программирования. Т.е. в оптимизации есть несколько стадий, не следует этого забывать.

Для самих выражений есть несколько очевидных правил:
  1. Литеральный поиск самый быстрый — /aa/ обычно быстрее /а{2}/ или /[a]{2}/
  2. Поиск данных неопределенной длинны расточителен (во всяком случае для HKA-версий). Если Вам известен размер данных — укажите его хотя-бы примерно. /\w{3,500}/ быстрее /\w+/
  3. Наличие скобок (и несохраняющих! тоже) замедляет поиск. Если Вам не нужна информация — никогда не заключайте сегмент в сохраняющие скобки и пытайтесь переписать шаблон для отказа и от несохраняющих. Требование иногда невозможное, но стоит иметь его ввиду. Кроме того, не стоит пытаться “помочь” машине регулярных выражений с поиском конструкциями типа /(?:.*)one/, это только запутает автомат.
  4. Наличие исполняемого кода в “теле” самого выражения или в “теле” выражения для подстановки — разорительны. Используйте эту технику только в том случае, если Вы абсолютно убеждены, что другого выхода нет. Положим, идея “оседлать” неявный цикл выражения с ключом /g — зачастую(JavaScript — точно) пустая трата времени. “Нативные” циклы базового языка вероятнее всего будут на порядок-другой быстрее, чем вход-выход в процессе работы машины регулярного выражения.
  5. Выражения “замены” гораздо медленнее выражений поиска. В случае замены больших кусков текста имеет смысл подумать об альтернативном варианте с созданием новой версии текста. Может оказаться сложнореализуемым, но имеет смысл хотя бы задуматься о такой проблеме.
  6. Альтернативы замедляют поиск, альтернативы неизвестной длины настолько его замедляют, что иногда следует попробовать искать в несколько проходов безальтернативной конструкцией.
  7. Не забывайте пользоваться “якорями” начала /^/ и конца /$/ строки, если они могут быть применены в Вашем случае.
  8. Конструкции “заглядывания” назад и вперед обычно плохо сказываются на скорости. Попробуйте сформулировать шаблон точнее.
  9. Не пользуйтесь конструкциями $` и $’ (в JavaScript это RegExp.leftContext и RegExp.rightContext) — они могут сильно замедлить разбор.

Основная идея — чем точнее вы объясняете, что именно нужно снять с верхней полки, тем меньше времени простоите перед прилавком. Не забывайте, лучше услышать сразу “пивом не торгуем” в булочной, чем 20 минут гонять продавца по всем стеллажам с просьбой “дайте мне такую хрень, не знаю как объяснить…” с тем же результатом. Чем ближе Ваш шаблон будет к созданию бинарного решения ЕСТЬ-НЕТ при его применении к тексту ЦЕЛИКОМ, тем лучше.
В отношении частной оптимизации к конкретному языку программирования — все до неприличия непросто. Старайтесь ориентироваться на минимализацию возвращаемых данных. К примеру — нет смысла выполнять оператор замены, дабы выяснить совпадет ли шаблон. Да и само совпадение можно попробовать выяснить наименее “говорливым” оператором. Положим, в JavaScript есть оператор .test который сообщает только “совпало-не совпало”. Если это единственное, что Вас интересует — используйте его, а не .match или .exec. Полагаю, что особенно ценен этот совет может оказаться для пользователей PHP с его бестиарием regex-like операторов.
Данная заметка не претендует ни на что, кроме как заставить читателя(да и писателя тоже) задуматься о процессе оптимизации такого мощного инструмента, как регулярные выражения.
Задумались? Перечитайте Фридла с его “Регулярными выражениями”, а если такой книжки еще нет — немедля прикупите!
Tags:
Hubs:
+29
Comments26

Articles