我需要匹配所有这些开头标记:

<p>
<a href="foo">

但不是这些:

<br />
<hr class="foo" />

我想出了这个,想确保我做得对。我只是在捕捉a-z。

<([a-z]+) *[^/]*?>

我相信上面写着:

找到一个小于,然后查找(并捕获)a-z一次或多次,然后找到零个或多个空格,然后查找任何字符零次或多次,贪婪,除了/,然后查找大于

我有这个权利吗?更重要的是,你怎么看?


当前回答

我喜欢用正则表达式解析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解析器上的火焰大战是怎么回事?HTML解析器必须解析(并重建!)整个文档,然后才能对搜索进行分类。在某些情况下,正则表达式可能更快/更优雅。我的2美分。。。

我喜欢用正则表达式解析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是不可能的,但有时使用它们来解析一组有限的已知HTML是合适的。

如果您有一小组HTML页面,希望从中提取数据,然后将其填充到数据库中,正则表达式可能会很好地工作。例如,我最近想获得澳大利亚联邦代表的姓名、党派和选区,这是我从议会网站上得到的。这是一份有限的一次性工作。

Regexes对我来说很好,而且安装速度很快。

我认为这里的缺陷是HTML是Chomsky Type 2语法(上下文无关语法),正则表达式是ChomskyType 3语法(正则语法)。由于第2类语法从根本上比第3类语法更复杂(请参见乔姆斯基层次结构),因此不可能实现这一点。

但很多人会尝试,有些人甚至会声称成功,但直到其他人发现错误并将你彻底搞砸。

正如许多人已经指出的那样,HTML不是一种常规语言,这会使解析变得非常困难。我的解决方案是使用整洁的程序将其转换为常规语言,然后使用XML解析器来使用结果。有很多好的选择。我的程序使用Java和jtidy库编写,将HTML转换为XML,然后Jaxen将其展开为结果。