我需要匹配所有这些开头标记:
<p>
<a href="foo">
但不是这些:
<br />
<hr class="foo" />
我想出了这个,想确保我做得对。我只是在捕捉a-z。
<([a-z]+) *[^/]*?>
我相信上面写着:
找到一个小于,然后查找(并捕获)a-z一次或多次,然后找到零个或多个空格,然后查找任何字符零次或多次,贪婪,除了/,然后查找大于
我有这个权利吗?更重要的是,你怎么看?
我需要匹配所有这些开头标记:
<p>
<a href="foo">
但不是这些:
<br />
<hr class="foo" />
我想出了这个,想确保我做得对。我只是在捕捉a-z。
<([a-z]+) *[^/]*?>
我相信上面写着:
找到一个小于,然后查找(并捕获)a-z一次或多次,然后找到零个或多个空格,然后查找任何字符零次或多次,贪婪,除了/,然后查找大于
我有这个权利吗?更重要的是,你怎么看?
当前回答
如果您只需要标记名,那么应该可以通过正则表达式执行此操作。
<([a-zA-Z]+)(?:[^>]*[^/] *)?>
应该做你需要的事。但我认为“莫里茨”的解决方案已经很好了。我一开始没看到。
对于所有反对者:在某些情况下,使用正则表达式是有意义的,因为这可能是最简单、最快捷的解决方案。我同意一般情况下不应该用正则表达式解析HTML。
但是当你有一个HTML子集,你知道格式并且你只想提取一些值时,正则表达式可以是一个非常强大的工具。我这样做了数百次,几乎总是达到我想要的目的。
其他回答
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');
$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';
$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
$nodeName = strtolower($el->nodeName);
if ( !in_array( $nodeName, $selfClosing ) ) {
var_dump( $nodeName );
}
}
输出:
string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"
基本上,只需定义自关闭的元素节点名称,将整个html字符串加载到DOM库中,抓取所有元素,循环并过滤掉不自关闭的并对其进行操作。
我确信您现在已经知道不应该为此使用正则表达式。
我喜欢用正则表达式解析HTML。我不会试图解析故意破坏的白痴HTML。这段代码是我的主解析器(Perl版):
$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print
它被称为htmlsplit,将HTML拆分为多行,每行上有一个标记或文本块。然后可以使用其他文本工具和脚本(如grep、sed、Perl等)进一步处理这些行。
如果您希望处理巨大的网页,将我的slurp一切第一个Perl脚本重新设置为一个不错的流式处理就足够简单了。但这不是真的必要。
HTML拆分
一些更好的正则表达式:
/(<.*?>|[^<]+)\s*/g # Get tags and text
/(\w+)="(.*?)"/g # Get attibutes
它们适用于XML/XTML。
通过小的变化,它可以处理杂乱的HTML。。。或者先转换HTML->XHTML。
编写正则表达式的最佳方式是使用Lex/Yacc样式,而不是不透明的单行或注释的多行怪物。我还没有在这里这样做;这些人几乎不需要它。
我认为这里的缺陷是HTML是Chomsky Type 2语法(上下文无关语法),正则表达式是ChomskyType 3语法(正则语法)。由于第2类语法从根本上比第3类语法更复杂(请参见乔姆斯基层次结构),因此不可能实现这一点。
但很多人会尝试,有些人甚至会声称成功,但直到其他人发现错误并将你彻底搞砸。
中国古代军事家、将军和哲学家孙子说过:
据说,如果你了解你的敌人,了解你自己,你可以赢得百战百胜,而不会一败涂地。如果你只了解自己,而不了解对手,你可能会赢,也可能会输。如果你既不了解你自己也不了解你的敌人,你将永远危及自己。
在这种情况下,你的敌人是HTML,你要么是你自己,要么是正则表达式。您甚至可能是带有不规则正则表达式的Perl。了解HTML。了解自己。
我写了一首描述HTML本质的俳句。
HTML has
complexity exceeding
regular language.
我还写了一首俳句,描述Perl中正则表达式的性质。
The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>
尽管为此目的使用正则表达式并不合适和有效,但有时正则表达式为简单的匹配问题提供了快速解决方案,在我看来,将正则表达式用于琐碎的工作并不可怕。
有一篇关于匹配StevenLevithan编写的最内部HTML元素的权威博客文章。