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


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

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

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

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

5 94

5 ответов:

обычно с помощью tokeniser. Проект спецификация HTML5 имеет обширный алгоритм для обработки "реального мира HTML".

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

Ну, нет.

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

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

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

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

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

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

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

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

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

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

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

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

но так же и это:

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

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