Регулярное выражение для соответствия всем тегам HTML, кроме <p> и </p>

StackOverflow https://stackoverflow.com/questions/29869

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

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

Это было полезно?

Решение 3

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

<(?!\/?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 с атрибутами или без них и закрывающим тегам p, но будет соответствовать предварительным и аналогичным тегам с атрибутами или без них.

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

Другие советы

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

# 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::ТокеПарсер модуль, который поставляется с чрезвычайно мощным HTML::Парсер Распространение 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::Парсер принимает входные данные в виде имени файла, дескриптора открытого файла или строки.Обернуть приведенный выше код в библиотеку и сделать пункт назначения настраиваемым (т. е. не просто printкак описано выше) не сложно.Результат будет гораздо более надежным, удобным в обслуживании и, возможно, более быстрым (HTML::Parser использует серверную часть на основе C), чем попытка использовать регулярные выражения.

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

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

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

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

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

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

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

Не знаю, почему вы хотите это сделать — регулярное выражение для очистки 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
    >               # >
)

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

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

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

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

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

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

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

Поскольку HTML не является обычным языком

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

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

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

РЕДАКТИРОВАТЬ:

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

Это, наверное?

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

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

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

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

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

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

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

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

Несмотря на все заявления об использовании регулярных выражений для анализа 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

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

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

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

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

/РЕДАКТИРОВАТЬ:Я добавил возможность обрабатывать атрибуты в p теги.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top