Как использовать Perl Regex для обнаружения <p>внутри другого <p> - PullRequest
0 голосов
/ 18 февраля 2011

Я пытаюсь проанализировать "неправильный HTML", чтобы исправить это с помощью регулярного выражения Perl.Неправильный HTML-код выглядит следующим образом: <p>foo<p>bar</p>foo</p>

Я хотел бы, чтобы Perl Regex возвращал мне: <p>foo<p>

Я пробовал что-то вроде: '|(<p\b[^>]*>(?!</p>)*?<p[^>]*>)|' безуспешно, потому что я не могу повторить(?!</p>)*?

Есть ли способ в Perl Regex сказать все символы, кроме следующей последовательности (в моем случае </p>)

Ответы [ 5 ]

1 голос
/ 02 марта 2011

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

Внимательно посмотрите на HTML :: TreeBuilder :: XPath и HTML :: DOM для внесения структурных изменений в документы HTML.

1 голос
/ 18 февраля 2011

Попробуйте что-то вроде:

<p>(?:(?!</?p>).)*</p>(?!(?:(?!</?p>).)*(<p>|$))

Быстрый отказ:

<p>(?:(?!</?p>).)*</p>

соответствует <p> ... </p>, что не содержит <p> и </p>.И часть:

(?!(?:(?!</?p>).)*(<p>|$))

является «истинной», если смотреть в будущее ((?! ... )), нет <p> или конца ввода ((<p>|$)), без каких-либо <p> и </p> между ((?:(?!</?p>).)*).

Демонстрационная версия:

my $txt="<p>aaa aa a</p> <p>foo <p>bar</p> foo</p> <p> bb <p>x</p> bb</p>";
while($txt =~ m/(<p>(?:(?!<\/?p>).)*<\/p>)(?!(?:(?!<\/?p>).)*(<p>|$))/g) {
  print "Found: $1\n";
}

печатает:

Found: <p>bar</p>
Found: <p>x</p>

Обратите внимание, что эта хитрость регулярного выражения работает только для <p>baz</p> в строке:

<p>foo <p>bar</p> <p>baz</p> foo</p>

<p>bar</p> не соответствует!После замены <p>baz</p> вы можете выполнить второй запуск на входе, в этом случае <p>bar</p> будет сопоставлено.

0 голосов
/ 02 марта 2011

Возможно, Marpa::HTML поможет вам. Прочитайте некоторые интересные способности, которые есть у него на блоге автора об этом . Суть в том, что синтаксический анализатор работает с интерпретатором (я, вероятно, получаю неверную семантику), чтобы выяснить, что должно присутствовать, исходя из того, что МОЖЕТ присутствовать в определенном логическом месте кода.

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

Marpa::HTML поставляется с утилитой командной строки, построенной с использованием модуля под названием html_fmt. Это реализует механизм синтаксического анализа, чтобы исправить и распечатать html. Вот пример. Если 'bad.html' содержит <p>foo<p>bar</p>foo</p>, то html_fmt bad.html дает:

<!-- Following start tag is replacement for a missing one -->
<html>
  <!-- Following start tag is replacement for a missing one -->
  <head>
  </head>
  <!-- Preceding end tag is replacement for a missing one -->
  <!-- Following start tag is replacement for a missing one -->
  <body>
    <p>
      foo
    </p>
    <!-- Preceding end tag is replacement for a missing one -->
    <p>
      bar
    </p>
    foo
    <!-- Next line is cruft -->
    </p>
  </body>
  <!-- Preceding end tag is replacement for a missing one -->
</html>
<!-- Preceding end tag is replacement for a missing one -->
0 голосов
/ 02 марта 2011

Если вы пытаетесь проверить HTML, рассмотрите такой модуль, как HTML :: Tidy или HTML :: Lint .

0 голосов
/ 18 февраля 2011

Это регулярное выражение:

<p>(?:(?!</p>).)*?<p>

при совпадении с

<p>foo<p>bar</p>foo</p>

Результаты в

<p>foo<p>
...