正则表达式以匹配除和以外的所有HTML标记
我需要在Perl中使用正则表达式匹配并删除所有标签。我有以下内容:
<\??(?!p).+?>
但这仍与结束标记</ p>匹配。关于如何与结束标记匹配的任何提示?
注意,这是在xhtml上执行的。
解决方案
回答
假定这将在PERL中起作用,就像在声称使用PERL兼容语法的语言中一样:
/ <\ /?[^ p] [^>] *> /
编辑:
不幸的是,但这与<pre>
或者<param>
标签不匹配。
这也许吗?
/<\/?(?!p>|p )[^>]+>/
那应该也包含具有属性的<p>
标签。
回答
试试这个,它应该可以工作:
/<\/?([^p](\s.+?)?|..+?)>/
说明:它匹配除p之外的单个字母,后跟可选的空格和更多字符,或者多个字母(至少两个)。
/ EDIT:我已经添加了处理" p"标签中的属性的功能。
回答
由于HTML不是常规语言,因此我不希望正则表达式在匹配它方面做得很好。他们也许有能力完成这项任务(尽管我不敢相信),但我会考虑在其他地方寻找。我确信perl必须有一些现成的库来处理HTML。
无论如何,我认为我们要匹配的是</?(p。+ |。*)(\ s 。)>非贪婪地(我不知道perl的regexp语法有多变,所以我无济于事进一步)。我假设\ s表示空白。也许不是。无论哪种方式,我们都需要某种与标记名称偏移了空白的属性相匹配的东西。但这比这更困难,因为人们经常在脚本和注释甚至是引用的属性值中放上未转义的尖括号,而这是我们不希望与之匹配的。
因此,正如我所说,我真的不认为正则表达式是完成这项工作的正确工具。
回答
Since HTML is not a regular language
HTML不是,但HTML标记是HTML,它们可以用正则表达式适当地描述。
回答
我们可能还应该删除<p>标记上的所有属性,因为不好的人可能会执行以下操作:
<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>
最简单的方法是使用此处建议的正则表达式搜索带有属性的&ltp>标记,然后将其替换为没有属性的<p>标记。只是为了安全起见。
回答
我想出了这个:
<(?!\/?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标记,但将匹配具有或者不具有属性的前置和相似标签。
它不会删除属性,但是我的源数据不会将它们放入。稍后我可能会更改它以执行此操作,但是现在就足够了。
回答
不确定为什么要为此正则表达式进行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 > # > )
回答
如果我们坚持使用正则表达式,则在大多数情况下将可以使用以下方法:
# 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接受文件名,打开的文件句柄或者字符串形式的输入。将上面的代码包装到库中并使目标可配置(即,不仅像上面那样"打印")并不难。结果将比尝试使用正则表达式更加可靠,可维护,并且可能更快(HTML :: Parser使用基于C的后端)。
回答
我们可能还希望在p标记中的" p"之前留空白。不确定我们会遇到这种情况的频率,但是<p>是完全有效的HTML。
回答
在我看来,尝试使用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解析器非常容易。
回答
原始的正则表达式可以非常轻松地工作:
<(?>/?)(?!p).+?>
问题是/? (或者\?)在断言失败后放弃匹配的内容。在其周围使用非回溯组(?> ...)时要注意,它绝不会释放匹配的斜杠,因此(?!p)断言始终锚定在标记文本的开头。
(也就是说,我同意通常不使用正则表达式解析HTML)。
回答
我使用了Xetius regex,它工作正常。除了一些flex生成的标签,它们可以是:
里面没有空格。我试着用简单的方法修复它?在\ s之后,看起来好像正在工作:
<(?!\/?p(?=>|\s?.*>))\/?.*?>
我用它来清除flex生成的html文本中的标签,所以我还添加了更多例外标签:
<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>