Regex соответствует всем тэгам HTML, кроме <p>и</p>

Мне нужно сопоставить и удалить все теги, используя регулярное выражение в Perl. У меня есть следующее:

<\\??(?!p).+?>

Но это все равно совпадает с закрывающим тегом </p>. Любой намек на то, как совпадать с закрывающим тегом?

Обратите внимание, что это выполняется в xhtml.

Ответ 1

Я придумал это:

<(?!\/?p(?=>|\s.*>))\/?.*?>

x/
<           # Match open angle bracket
(?!         # Negative lookahead (Not matching and not consuming)
    \/?     # 0 or 1 /
    p           # p
    (?=     # Positive lookahead (Matching and not consuming)
    >       # > - No attributes
        |       # or
    \s      # whitespace
    .*      # anything up to 
    >       # close angle brackets - with attributes
    )           # close positive lookahead
)           # close negative lookahead
            # if we have got this far then we don't match
            # a p tag or closing p tag
            # with or without attributes
\/?         # optional close tag symbol (/)
.*?         # and anything up to
>           # first closing tag
/

Теперь мы будем иметь дело с p-тегами с атрибутами или без них и с закрывающими т-тегами, но будет соответствовать пред и аналогичным тегам с атрибутами или без них.

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

Ответ 2

Если вы настаиваете на использовании регулярного выражения, что-то вроде этого будет работать в большинстве случаев:

# Remove all HTML except "p" tags
$html =~ s{<(?>/?)(?:[^pP]|[pP][^\s>/])[^>]*>}{}g;

Пояснение:

s{
  <             # opening angled bracket
  (?>/?)        # ratchet past optional / 
  (?:
    [^pP]       # non-p tag
    |           # ...or...
    [pP][^\s>/] # longer tag that begins with p (e.g., <pre>)
  )
  [^>]*         # everything until closing angled bracket
  >             # closing angled bracket
 }{}gx; # replace with nothing, globally

Но на самом деле, спасите себе головные боли и вместо этого используйте парсер. CPAN имеет несколько подходящих модулей. Вот пример использования модуля HTML:: TokeParser, который поставляется с чрезвычайно способным HTML:: Parser Распространение CPAN:

use strict;

use HTML::TokeParser;

my $parser = HTML::TokeParser->new('/some/file.html')
  or die "Could not open /some/file.html - $!";

while(my $t = $parser->get_token)
{
  # Skip start or end tags that are not "p" tags
  next  if(($t->[0] eq 'S' || $t->[0] eq 'E') && lc $t->[1] ne 'p');

  # Print everything else normally (see HTML::TokeParser docs for explanation)
  if($t->[0] eq 'T')
  {
    print $t->[1];
  }
  else
  {
    print $t->[-1];
  }
}

HTML:: Parser принимает входные данные в виде имени файла, дескриптора открытого файла или строки. Обтекание вышеуказанного кода в библиотеке и создание настраиваемого адресата (т.е. Не только print ing, как в приведенном выше), не сложно. Результат будет намного более надежным, поддерживаемым и, возможно, быстрее (HTML:: Parser использует бэкэнд на основе C), чем пытается использовать регулярные выражения.

Ответ 3

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

Например, это:

<HTML /
  <HEAD /
    <TITLE / > /
    <P / >

- это полный 100% -ный корректный HTML-документ на 100%. (Ну, в нем отсутствует декларация DOCTYPE, но кроме этого...)

Он семантически эквивалентен

<html>
  <head>
    <title>
      &gt;
    </title>
  </head>
  <body>
    <p>
      &gt;
    </p>
  </body>
</html>

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

Ответ 4

Не уверен, почему вы хотите это сделать - регулярное выражение для санитарии HTML не всегда является лучшим методом (вам нужно помнить, что нужно дезинфицировать атрибуты и т.д., удалить javascript: hrefs и подобные)... но, регулярное выражение для соответствия тэгам HTML, которые не являются <p></p>:

(<[^pP].*?>|</[^pP]>)

Многословный:

(
    <               # < opening tag
        [^pP].*?    # p non-p character, then non-greedy anything
    >               # > closing tag
|                   #   ....or....
    </              # </
        [^pP]       # a non-p tag
    >               # >
)

Ответ 5

Я использовал регулярное выражение Xetius, и он отлично работает. За исключением некоторых сгенерированных сгенерированных тегов, которые могут быть:
без пробелов внутри. Я попробовал ti исправить это с помощью простого? после \s, и похоже, что он работает:

<(?!\/?p(?=>|\s?.*>))\/?.*?>

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

<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>

Ответ 6

Так как HTML не является обычным языком, я бы не ожидал, что регулярное выражение будет очень хорошо работать с ним. Они могут справиться с этой задачей (хотя я не уверен), но я бы подумал о том, чтобы искать в другом месте; Я уверен, что perl должен иметь некоторые готовые библиотеки для управления HTML.

Во всяком случае, я бы подумал, что то, что вы хотите совместить, равно </? (p. + |. *) (\ s *. *) > не жадность (я не знаю капризы синтаксиса perl regexp, поэтому я не могу помочь дальше). Я предполагаю, что \s означает пробелы. Возможно, нет. В любом случае вам нужно что-то, что будет соответствовать атрибутам, смещенным от имени тега по пробелам. Но это сложнее, чем в том случае, когда люди часто помещают неэкранированные угловые скобки внутри сценариев и комментариев и, возможно, даже цитируют значения атрибутов, с которыми вы не хотите сопоставлять.

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

Ответ 7

Так как HTML не является регулярным языком

HTML - это не теги HTML, и они могут быть адекватно описаны регулярными выражениями.

Ответ 8

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

/<\/?[^p][^>]*>/

EDIT:

Но это не соответствует тегу <pre> или <param>, к сожалению.

Это, возможно?

/<\/?(?!p>|p )[^>]+>/

Это должно охватывать теги <p>, которые также имеют атрибуты.

Ответ 9

Вы также можете разрешить пробелы перед "p" в теге p. Не уверен, как часто вы столкнетесь с этим, но <p> является вполне допустимым HTML.

Ответ 10

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

 <(?>/?)(?!p).+?>

Проблема заключалась в том, что /? (или \?) отказался от того, что он сопоставил, когда утверждение после его отказа. Используя группу без обратной отслеживания (? > ...) вокруг нее, она заботится о том, чтобы она никогда не выпускала совпадающую косую черту, поэтому утверждение (?! P) всегда привязывается к началу текста тега.

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

Ответ 11

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

При всех отказах в использовании regex для синтаксического анализа html, это простой способ сделать это.

#!/usr/bin/perl
$regex = '(<\/?p[^>]*>)|<[^>]*>';
$subject = 'Bad html <a> </I> <p>My paragraph</p> <i>Italics</i> <p class="blue">second</p>';
($replaced = $subject) =~ s/$regex/$1/eg;
print $replaced . "\n";

Смотрите эту живую демонстрацию

Ссылка

Как сопоставить шаблон, за исключением ситуаций s1, s2, s3

Как сопоставить шаблон, если...

Ответ 12

Попробуйте это, он должен работать:

/<\/?([^p](\s.+?)?|..+?)>/

Объяснение: оно соответствует либо одной букве, за исключением "p", за которой следуют необязательные пробелы и больше символов, или несколько букв (не менее двух).

/EDIT: я добавил способность обрабатывать атрибуты в тегах p.

Ответ 13

Вероятно, вы также должны удалить любые атрибуты в теге <p> так как кто-то плохо может сделать что-то вроде:

<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>

Самый простой способ сделать это - использовать люди регулярных выражений, предлагающие здесь искать теги & ltp > с атрибутами и заменять их тегами <p> без атрибутов. Просто чтобы быть в безопасности.