我需要在Perl中使用正则表达式匹配并删除所有标记。我有以下内容:
<\\??(?!p).+?>
但这仍然与结束</p>
标记匹配。关于如何与结束标签匹配的任何提示?
请注意,这是在xhtml上执行的。
答案 0 :(得分:37)
如果你坚持使用正则表达式,大多数情况下这样的东西都会起作用:
# 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 CPAN分发版附带的HTML::Parser模块的示例:
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
)并不难。与尝试使用正则表达式相比,结果将更可靠,可维护,并且可能也更快(HTML :: Parser使用基于C的后端)。
答案 1 :(得分:16)
在我看来,尝试用HTML解析器以外的任何东西解析HTML只是在寻求一个痛苦的世界。 HTML是一种真正的复杂语言(这是创建XHTML的主要原因之一,它比HTML简单得多)。
例如,这个:
<HTML /
<HEAD /
<TITLE / > /
<P / >
是一个完整的,100%格式良好,100%有效的HTML文档。 (好吧,它缺少DOCTYPE声明,但除此之外......)
它在语义上等同于
<html>
<head>
<title>
>
</title>
</head>
<body>
<p>
>
</p>
</body>
</html>
但它仍然是有效的HTML,你将不得不处理。当然,你可以设计一个正则表达式来解析它,但是,正如其他人已经建议的那样,使用实际的HTML解析器要简单得多。
答案 2 :(得分:10)
我想出了这个:
<(?!\/?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标签,但会匹配pre和类似标签,有或没有属性。
它不会删除属性,但我的源数据不会将它们放入。我可能会在稍后更改它,但现在就足够了。
答案 3 :(得分:3)
不确定为什么要这样做 - HTML清理的正则表达并不总是最好的方法(你需要记住清理属性等,删除javascript:hrefs等等)...但是,一个正则表达式匹配不是<p></p>
的HTML标记:
(<[^pP].*?>|</[^pP]>)
详细:
(
< # < opening tag
[^pP].*? # p non-p character, then non-greedy anything
> # > closing tag
| # ....or....
</ # </
[^pP] # a non-p tag
> # >
)
答案 4 :(得分:3)
我使用Xetius正则表达式并且工作正常。除了一些flex生成的标签,它们可以是:
内部没有空格。我尝试在 \ s 之后用一个简单的?修复它,看起来它正在工作:
<(?!\/?p(?=>|\s?.*>))\/?.*?>
我用它来清除flex生成的html文本中的标签,所以我还添加了更多的例外标签:
<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>
答案 5 :(得分:2)
由于HTML不是常规语言,我不希望正则表达式在匹配它时做得很好。他们可能完成这项任务(虽然我不相信),但我会考虑寻找其他地方;我确信perl必须有一些现成的库来操作HTML。
无论如何,我认为你想要匹配的是&lt; /?(p。+ |。*)(\ s *。*)&gt;非贪婪(我不知道perl的regexp语法的变幻莫测,所以我无法进一步帮助)。我假设\ s表示空格。也许它没有。无论哪种方式,您都希望通过空格匹配与标记名称相关的属性。但它比这更困难,因为人们经常将未转义的尖括号放在脚本和注释中,甚至可能引用属性值,这是你不想匹配的。
正如我所说,我并不认为正则表达式是适合这项工作的正确工具。
答案 6 :(得分:2)
由于HTML不是常规语言
HTML不是HTML标签,而且正则表达式可以充分描述它们。
答案 7 :(得分:1)
假设这可以在PERL中使用,就像声称使用PERL兼容语法的语言一样:
/<\/?[^p][^>]*>/
编辑:
但遗憾的是,这与<pre>
或<param>
标记不匹配。
这可能呢?
/<\/?(?!p>|p )[^>]+>/
这应该涵盖具有属性的<p>
标记。
答案 8 :(得分:1)
您还可能希望在p标记中的“p”之前允许空格。不知道你会经常遇到这种情况,但是&lt; p为H.是完全有效的HTML。
答案 9 :(得分:1)
原始的正则表达式可以很轻松地工作:
<(?>/?)(?!p).+?>
问题是/? (或\?)放弃了失败后的断言所匹配的内容。在它周围使用非回溯组(?> ...)时要注意它永远不会释放匹配的斜杠,因此(?!p)断言始终锚定在标记文本的开头。
(那表示我同意通常用正则表达式解析HTML不是一种方法)。
答案 10 :(得分:1)
关于使用正则表达式解析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";
请参阅此live demo
参考
答案 11 :(得分:0)
试试这个,它应该有效:
/<\/?([^p](\s.+?)?|..+?)>/
说明:它匹配除“p”之外的单个字母,后跟可选的空格和更多字符,或多个字母(至少两个)。
/编辑:我添加了处理p
代码中的属性的功能。
答案 12 :(得分:0)
这对我有用,因为对于其他以 p 开头的 html 标签(例如 param pre progress 等),上述所有解决方案都失败了。它也处理了 html 属性。
~(<\/?[^>]*(?<!<\/p|p)>)~ig
答案 13 :(得分:-1)
您可能还应删除&lt; p&gt;上的所有属性。标签,因为有人可能会做类似的事情:
<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>
最简单的方法是使用人们在此处建议的正则表达式来搜索&amp; ltp&gt;带有属性的标记,并将其替换为&lt; p&gt;没有属性的标签。为了安全起见。