Как работают анализы HTML, если они не используют regexp?

Я каждый день вижу вопросы о том, как анализировать или извлекать что-то из некоторой строки HTML, а первый ответ/комментарий всегда "Не используйте RegEx для анализа HTML, чтобы вы не чувствовали гнев!" (последняя часть иногда опускается).

Это довольно сбивает меня с толку, я всегда думал, что в целом лучший способ разобрать любую сложную строку - использовать регулярное выражение. Итак, как работает парсер HTML? Не использует ли регулярные выражения для синтаксического анализа.

Один конкретный аргумент для использования регулярного выражения состоит в том, что не всегда существует альтернатива синтаксического анализа (например, JavaScript, где DOMDocument не является универсальным вариантом). Например, jQuery отлично справляется с использованием регулярного выражения для преобразования строки HTML в узлы DOM.

Не уверен, что это CW, это настоящий вопрос, на который я хочу ответить, а не на самом деле предназначен для обсуждения.

Ответ 2

Итак, как работает парсер HTML? Разве он не использует регулярные выражения для синтаксического анализа?

Ну, нет.

Если вы вернетесь в своем мозгу к теории вычислений, если вы возьмете один или курс компиляторов или что-то подобное, вы можете вспомнить, что существуют разные типы языков и вычислительные модели. Я не имею права во всех подробностях, но я могу рассмотреть несколько основных моментов с вами.

Самый простой тип языка и вычисление (для этих целей) - это обычный язык. Они могут быть сгенерированы с регулярными выражениями и распознаны с помощью конечных автоматов. В принципе, это означает, что "синтаксический анализ" строк на этих языках использует состояние, но не вспомогательную память. HTML, конечно, не является обычным языком. Если вы подумаете об этом, список тегов можно вложить в произвольно глубоко. Например, таблицы могут содержать таблицы, и каждая таблица может содержать много вложенных тегов. С помощью регулярных выражений вы можете выбрать пару тегов, но, конечно же, ничего не произвольно вложенное.

Классический простой язык, который не является регулярным, - это правильные совпадающие круглые скобки. Попробуйте, как вы могли бы, вы никогда не сможете построить регулярное выражение (или конечный автомат), который всегда будет работать. Вам нужна память, чтобы отслеживать глубину вложенности.

Конечным автоматом со стеком для памяти является следующая сила вычислительной модели. Это называется push-down automaton, и он распознает языки, генерируемые контекстно-свободными грамматиками. Здесь мы можем распознавать правильно сопоставленные скобки - действительно, стек - идеальная модель памяти для него.

Хорошо, это достаточно хорошо для HTML? К сожалению нет. Возможно, для супер-пупер тщательно проверенного XML, на самом деле, в котором все теги всегда выстраиваются идеально. В реальном HTML-тексте вы можете легко найти фрагменты типа <b><i>wow!</b></i>. Очевидно, это не гнездо, поэтому для правильного его анализа стек просто недостаточно эффективен.

Следующий уровень вычислений - это языки, сгенерированные общими грамматиками, и распознаваемые машинами Тьюринга. Общепризнанно, что он является самой сильной вычислительной моделью - это машина состояний с дополнительной памятью, чья память может быть изменена в любом месте. Это то, что языки программирования могут делать. Это уровень сложности, в котором живет HTML.

Подводя итог всему здесь в одном предложении: для анализа общего HTML вам нужен настоящий язык программирования, а не регулярное выражение.

HTML анализируется так же, как анализируются другие языки: лексирование и синтаксический анализ. Шаг лексики разбивает поток отдельных символов на значащие токены. Шаг синтаксического анализа собирает токены, используя состояния и память, в логически когерентный документ, на котором можно действовать.

Ответ 3

Регулярные выражения - это всего лишь одна форма анализатора. Парсер откровенного HTML-качества будет значительно сложнее, чем может быть выражен в регулярных выражениях, используя рекурсивный спуск, прогнозирование и несколько других методов для правильно интерпретировать текст. Если вы действительно хотите войти в него, вы можете проверить lex и yacc и аналогичные инструменты.

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

Ответ 4

Анализ HTML - это преобразование линейного текста в древовидную структуру. Регулярные выражения обычно не могут обрабатывать древовидные структуры. Регулярное выражение, которое вам нужно в каждой точке, чтобы постоянно менять следующий токен. Вы можете использовать регулярные выражения в синтаксическом анализаторе, но для каждого возможного состояния разбора вам понадобится целый массив регулярных выражений.

Ответ 5

Если вы хотите иметь 100% -ное решение: вам нужно написать свой собственный код, который повторяется с помощью символьного символа HTML, и вам нужно иметь огромное количество логики, чтобы определить, следует ли остановить текущий node и запустите следующий.

Причина в том, что это допустимо HTML:

<ul>
<li>One
<li>Two
<li>Three
</ul>

Но так вот:

<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>

Если вы в порядке с "90% -ным решением": тогда использование XML-парсера для загрузки документа в порядке. Или с помощью Regex (хотя xml проще, если вы тогда владеете содержимым).