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

Одна ошибка, которую я вижу, что люди делают снова и снова, это попытка разобрать XML или HTML с помощью регулярного выражения. Вот несколько причин, по которым сложно анализировать XML и HTML:

Люди хотят рассматривать файл как последовательность строк, но это действительно так:

<tag
attr="5"
/>

Люди хотят рассматривать тег <или <как начало тега, но такие вещи существуют в дикой природе:

<img src="imgtag.gif" alt="<img>" />

Люди часто хотят сопоставить начальные и конечные теги, но XML и HTML позволяют тегам содержать себя (что традиционные регулярные выражения вообще не могут обработать):

<span id="outer"><span id="inner">foo</span></span> 

Люди часто хотят сопоставить содержимое документа (например, известную проблему "найти все номера телефонов на данной странице"), но данные могут быть размечены (даже если они выглядят нормальными при просмотре):

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

Комментарии могут содержать плохо отформатированные или неполные теги:

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

Какие еще ошибки вы знаете?

12 ответов

Решение

Вот забавный действительный XML для вас:

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

И этот маленький пучок радости является действительным HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

Не говоря уже о браузерском разборе недействительных конструкций.

Удачи в борьбе с этим!

РЕДАКТИРОВАТЬ (Jörg W Mittag): Вот еще один хороший кусок правильно оформленного, верного HTML 4.01:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>

На самом деле

<img src="imgtag.gif" alt="<img>" />

не является допустимым HTML, а также не является допустимым XML.

Это недопустимый XML, потому что '<' и '>' не являются допустимыми символами внутри строк атрибута. Их нужно экранировать, используя соответствующие объекты XML & lt; и & gt;

Это также недопустимый HTML, поскольку в HTML недопустима короткая закрывающая форма (но она верна в XML и XHTML). Тег 'img' также является неявно закрытым тегом согласно спецификации HTML 4.01. Это означает, что закрытие вручную на самом деле неверно и эквивалентно закрытию любого другого тега дважды.

Правильная версия в HTML

<img src="imgtag.gif" alt="&lt;img&gt;">

и правильная версия в XHTML и XML

<img src="imgtag.gif" alt="&lt;img&gt;"/>

Приведенный ниже пример также недействителен

<
tag
attr="5"
/>

Это не допустимый HTML или XML либо. Имя тега должно быть сразу за "<", хотя атрибуты и закрывающий ">" могут быть где угодно. Таким образом, действительный XML на самом деле

<tag
attr="5"
/>

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

<img src="image.gif" alt='This is single quoted AND valid!'>

Все остальные причины, которые были опубликованы, верны, но самая большая проблема при разборе HTML заключается в том, что люди обычно не понимают все правила синтаксиса правильно. Тот факт, что ваш браузер интерпретирует ваш tagoup как HTML, не означает, что вы действительно написали правильный HTML.

Редактировать: И даже stackru.com соглашается со мной относительно определения действительных и недействительных. Ваш неверный XML/HTML не выделен, а моя исправленная версия -.

По сути, XML не предназначен для анализа с помощью регулярных выражений. Но нет также причин для этого. Существует множество синтаксических анализаторов XML для каждого языка. У вас есть выбор между парсерами SAX, DOM и парсерами Pull. Все они гарантированно будут выполняться намного быстрее, чем синтаксический анализ с помощью регулярного выражения, и тогда вы можете использовать классные технологии, такие как XPath или XSLT, в получающемся дереве DOM.

Поэтому я отвечаю: не только сложно анализировать XML с помощью регулярных выражений, но и это плохая идея. Просто используйте один из миллионов существующих анализаторов XML и воспользуйтесь всеми расширенными функциями XML.

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

Я написал целую запись в блоге на эту тему: Ограничения регулярных выражений

Суть проблемы в том, что HTML и XML являются рекурсивными структурами, для правильного анализа которых требуются механизмы подсчета. Истинное регулярное выражение не в состоянии считать. Вы должны иметь контекстно-свободную грамматику, чтобы считать.

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

Один недостаток, которого нет в вашем списке, заключается в том, что атрибуты могут появляться в любом порядке, поэтому, если ваше регулярное выражение ищет ссылку с href "foo" и классом "bar", они могут приходить в любом порядке и иметь любое количество других вещи между ними.

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

Люди на самом деле делают ошибку, используя регулярные выражения, или это просто достаточно хорошо для задачи, которую они пытаются достичь?

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

Однако, если ваше требование состоит не в разборе html / xml, а в том, чтобы просто получить один маленький бит данных в "хорошо известном" бите html / xml, тогда, возможно, достаточно регулярного выражения или даже еще более простой "подстроки".

Я испытываю желание сказать "не изобретай велосипед". За исключением того, что XML действительно очень сложный формат. Так что, может быть, я должен сказать "не изобретать синхротрон".

Возможно, правильное клише начинается "когда все, что у вас есть, это молоток…". Вы знаете, как использовать регулярные выражения, регулярные выражения хороши при разборе, так зачем же изучать библиотеку разбора XML?

Потому что разбирать XML сложно. Любые усилия, которые вы сэкономите, не изучая использование библиотеки синтаксического анализа XML, будут более чем компенсированы количеством творческой работы и выявлением ошибок, которые вам придется сделать. Ради себя, погуглите "XML-библиотеку" и используйте чужую работу.

Я думаю, что проблемы сводятся к:

  1. Регулярное выражение почти всегда неверно. Существуют допустимые входные данные, которые не могут быть правильно сопоставлены. Если вы достаточно усердно работаете, вы можете сделать это на 99% правильным, или на 99,999%, но сделать это на 100% правильным практически невозможно, хотя бы из-за странных вещей, которые XML допускает с помощью сущностей.

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

  3. Если регулярное выражение достаточно верно, чтобы охватить 99,99% случаев, оно будет полностью нечитаемым и недостижимым.

  4. Вполне вероятно, что регулярные выражения будут очень плохо работать с входными файлами среднего размера. Мое самое первое знакомство с XML состояло в том, чтобы заменить скрипт Perl, который (неправильно) анализировал входящие XML-документы, соответствующим анализатором XML, и мы не только заменили 300 строк нечитаемого кода на 100 строк, которые каждый мог понять, но мы улучшили время отклика пользователей. от 10 секунд до 0,1 секунды.

Обычно люди по умолчанию пишут жадные шаблоны, что часто приводит к непродуманному.* Превращению больших кусков файла в максимально возможный .*.

Я считаю, что у этого классика есть информация, которую вы ищете. Вы можете найти точку в одном из комментариев:

Я думаю, что недостаток в том, что HTML - это грамматика Chomsky Type 2 (контекстно-свободная грамматика), а RegEx - это грамматика Chomsky Type 3 (регулярное выражение). Поскольку грамматика типа 2 существенно сложнее, чем грамматика типа 3, вряд ли можно надеяться, что это сработает. Но многие попытаются, некоторые заявят об успехе, а другие найдут ошибку и полностью испортят вас.

Еще немного информации из Википедии: Хомская Иерархия

Я дал упрощенный ответ на эту проблему здесь. Хотя это и не учитывает 100% отметки, я объясняю, как это возможно, если вы готовы выполнить некоторую предварительную обработку.

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

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

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

Другие вопросы по тегам