← На главную

Парсить HTML регулярками реально, но лучше DOM-библиотекой

03.08.2026 08:47 · hackernews

Частый ответ на StackOverflow: HTML нельзя парсить регулярными выражениями, потому что HTML не регулярный. Это утверждение вводит в заблуждение. Формальные регулярные грамматики действительно слабы, но то, что программисты называют регулярными выражениями, к ним почти не относится. Современные движки вроде PCRE умеют гораздо больше.

В иерархии Хомского регулярные языки — лишь малый подкласс. PCRE может матчить все контекстно-свободные языки. Например, язык {a^n b^n} — классический контекстно-свободный, но не регулярный. Он матчится рекурсивным шаблоном /^(a(?1)?b)$/. Синтаксис DEFINE позволяет превратить любую контекстно-свободную грамматику в регулярное выражение. Так можно собрать полный парсер email из RFC 5322 — просто переписав BNF-правила в именованные подпаттерны. Единственное неудобство — левая рекурсия, но она всегда преобразуется в правую. Поэтому корректный HTML, который тоже контекстно-свободный, технически можно матчить регулярным выражением.

С контекстно-зависимыми языками сложнее. Некоторые матчатся: {a^n b^n c^n} — через lookahead-ассерции. Например, /^(?=(a(?-1)?b)c)a+(b(?-1)?c)$/x проверяет, что количество a, b и c совпадает. Но неизвестно, можно ли так сматчить все контекстно-зависимые языки. Основная проблема — lookbehind обязан быть фиксированной ширины.

Добавление backreferences делает регулярные выражения NP-полными. Это значит, что на regex можно решить любую NP-задачу, включая 3-CNF SAT. В статье показано, как булева формула превращается в выражение, которое находит выполняющий набор переменных. Правда, это скорее теоретическая возможность.

Вывод: мем про «нельзя парсить HTML регулярками» не совсем точен. Можно, но не всегда нужно. Для общего разбора HTML лучше взять DOM-библиотеку, она переживёт битый HTML. А для узкой конкретной задачи регулярное выражение часто проще. Используйте модификатор x и DEFINE, чтобы код оставался читаемым.

Читать оригинал →