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

<p>
<a href="foo">

但不是这些:

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

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

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

我相信上面写着:

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

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


当前回答

<([a-z][^>\s]*)(?:\s+[^>]+)?>

此正则表达式将匹配由单个单词(例如<p>、<a>等)组成的开头标记,后跟零个或多个空格和任意数量的字符(除了>或空白),然后是结束>字符。它还会将标记与属性匹配,并且不会将标记与包含a-z以外字符的名称匹配。然而,它仍然不会匹配自动关闭标签。

其他回答

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

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

我以前使用过一个名为HTMLParser的开源工具。它被设计为以各种方式解析HTML,并且很好地达到了目的。它可以将HTML解析为不同的树节点,您可以轻松地使用它的API从节点中获取属性。看看它,看看这对你有没有帮助。

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

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

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

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

我的建议是

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

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

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

虽然只有正则表达式的任意HTML是不可能的,但有时使用它们来解析一组有限的已知HTML是合适的。

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

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

的确,在编程时,在处理HTML时,最好使用专用解析器和API,而不是正则表达式,尤其是在准确性至关重要的情况下(例如,如果您的处理可能涉及安全问题)。然而,我并不认为XML风格的标记永远不应该用正则表达式来处理。在某些情况下,正则表达式是一个很好的工具,例如在文本编辑器中进行一次性编辑,修复损坏的XML文件,或者处理看起来像但不太像XML的文件格式。有一些问题需要注意,但它们并非不可逾越,甚至不一定相关。

像<([^>“']|”[^“]*”|'[^']*')*>这样的简单正则表达式通常足够好,例如我刚才提到的那些情况。这是一个天真的解决方案,但它确实允许在属性值中使用未编码的>符号。如果您正在查找,例如,表标签,您可以将其调整为</?表\b([^>“']|”[^“]*”|'[^']*')*>。

为了了解更“高级”的HTML正则表达式会是什么样子,以下内容在模拟真实世界的浏览器行为和HTML5解析算法方面做了相当出色的工作:

</?([A-Za-z][^\s>/]*)(?:=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|[^>])*(?:>|$)

以下内容与相当严格的XML标记定义相匹配(尽管它没有考虑XML名称中允许的全部Unicode字符集):

<(?:([_:A-Z][-.:\w]*)(?:\s+[_:A-Z][-.:\w]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*/?|/([_:A-Z][-.:\w]*)\s*)>

当然,这些不考虑周围的上下文和一些边缘情况,但如果您真的想处理这些问题(例如,通过在另一个正则表达式的匹配项之间进行搜索),也可以处理这些问题。

在一天结束时,使用最适合该作业的工具,即使该工具恰好是正则表达式。