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

<p>
<a href="foo">

但不是这些:

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

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

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

我相信上面写着:

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

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


当前回答

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

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

其他回答

如果您只是试图查找这些标记(没有解析的野心),请尝试以下正则表达式:

/<[^/]*?>/g

我在30秒内写下了它,并在这里进行了测试:http://gskinner.com/RegExr/

它匹配您提到的标记类型,而忽略您所说的要忽略的类型。

<\s*(\w+)[^/>]*>

各部分解释如下:

<:起始字符

\s*:标签名称前可能有空格(难看,但可能)。

(\w+):标记可以包含字母和数字(h1)。嗯,w也与“_”匹配,但我想它不会伤害你。如果好奇,请改用([a-zA-Z0-9]+)。

[^/>]*:除了>和/直到关闭>

>:关闭>

不相关的

对于那些低估了正则表达式的人来说,他们说正则表达式的功能和正则语言一样强大:

anbanban不是规则的,甚至不是上下文无关的,可以与^(a+)b\1b\1匹配$

反向引用FTW!

虽然不能用正则表达式解析HTML的答案是正确的,但它们在这里并不适用。OP只想用正则表达式解析一个HTML标记,这可以用正则表达式完成。

不过,建议的正则表达式是错误的:

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

如果你在正则表达式中添加了一些东西,通过回溯,它可能会被强制匹配像<a>>这样的愚蠢的东西,[^/]太宽容了。还要注意,<space>*[^/]*是冗余的,因为[^/]*也可以匹配空格。

我的建议是

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

其中(?<!…)是(在Perl正则表达式中)后面的否定外观。它的意思是“a<,然后是一个单词,然后是任何不是a>的东西,最后一个可能不是a/,后面是>”。

请注意,这允许使用<a/>(就像原始的正则表达式一样),因此如果您需要更严格的限制,则需要构建正则表达式以匹配由空格分隔的属性对。

尽管为此目的使用正则表达式并不合适和有效,但有时正则表达式为简单的匹配问题提供了快速解决方案,在我看来,将正则表达式用于琐碎的工作并不可怕。

有一篇关于匹配StevenLevithan编写的最内部HTML元素的权威博客文章。

如果您只需要标记名,那么应该可以通过正则表达式执行此操作。

<([a-zA-Z]+)(?:[^>]*[^/] *)?>

应该做你需要的事。但我认为“莫里茨”的解决方案已经很好了。我一开始没看到。

对于所有反对者:在某些情况下,使用正则表达式是有意义的,因为这可能是最简单、最快捷的解决方案。我同意一般情况下不应该用正则表达式解析HTML。

但是当你有一个HTML子集,你知道格式并且你只想提取一些值时,正则表达式可以是一个非常强大的工具。我这样做了数百次,几乎总是达到我想要的目的。