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>
>
</title>
</head>
<body>
<p>
>
</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> без атрибутов. Просто чтобы быть в безопасности.