我需要匹配所有这些开头标记:
<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一次或多次,然后找到零个或多个空格,然后查找任何字符零次或多次,贪婪,除了/,然后查找大于
我有这个权利吗?更重要的是,你怎么看?
当前回答
我同意解析XML,特别是HTML的正确工具是解析器,而不是正则表达式引擎。然而,正如其他人所指出的,有时使用正则表达式更快、更容易,并且如果您知道数据格式,就可以完成任务。
微软实际上有一节《.NET Framework中正则表达式的最佳实践》,专门讨论了“考虑输入源”。
正则表达式确实有局限性,但您是否考虑过以下问题?
在正则表达式方面,.NET框架是独一无二的,因为它支持平衡组定义。
请参见将平衡构造与.NET正则表达式匹配请参见.NET正则表达式:Regex和平衡匹配请参阅Microsoft关于平衡组定义的文档
因此,我相信您可以使用正则表达式解析XML。然而,请注意,它必须是有效的XML(浏览器对HTML非常宽容,并且允许HTML中有错误的XML语法)。这是可能的,因为“平衡组定义”将允许正则表达式引擎充当PDA。
引用上述第1条:
.NET正则表达式引擎如上所述,不能用正则表达式。但是,.NET正则表达式引擎提供了一些允许平衡构造辨识。(?<group>)-使用名称组。(?<-group>)-从捕获堆栈。(?(组)yes|no)-如果存在组,则匹配yes部分否则,名称组不匹配任何部分。这些构造允许.NET正则表达式模拟通过本质上允许简单版本的堆栈来限制PDA操作:推送、弹出和清空。简单的操作非常简单分别相当于递增、递减和比较为零。这允许.NET正则表达式引擎识别上下文无关语言的子集,特别是那些仅需要一个简单的计数器。这反过来允许非传统的.NET正则表达式,以识别各个正确平衡的构造。
考虑以下正则表达式:
(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
<!-- .*? --> |
<[^>]*/> |
(?<opentag><(?!/)[^>]*[^/]>) |
(?<-opentag></[^>]*[^/]>) |
[^<>]*
)*
(?(opentag)(?!))
使用标志:
单线IgnorePatternHitespace(如果折叠正则表达式并删除所有空格,则不需要)IgnoreCase(不需要)
正则表达式解释(内联)
(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?> # atomic group / don't backtrack (faster)
<!-- .*? --> | # match xml / html comment
<[^>]*/> | # self closing tag
(?<opentag><(?!/)[^>]*[^/]>) | # push opening xml tag
(?<-opentag></[^>]*[^/]>) | # pop closing xml tag
[^<>]* # something between tags
)* # match as many xml tags as possible
(?(opentag)(?!)) # ensure no 'opentag' groups are on stack
您可以在一个更好的.NET正则表达式测试仪上尝试。
我使用了以下示例源:
<html>
<body>
<div>
<br />
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
</div>
</body>
</html>
这找到了匹配项:
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
尽管它实际上是这样的:
<ul id="matchMe" type="square"> <li>stuff...</li> <li>more stuff</li> <li> <div> <span>still more</span> <ul> <li>Another >ul<, oh my!</li> <li>...</li> </ul> </div> </li> </ul>
最后,我真的很喜欢杰夫·阿特伍德的文章:解析Html的Cthhulhu方式。有趣的是,它引用了这个问题的答案,目前有超过4万张选票。
其他回答
Try:
<([^\s]+)(\s[^>]*?)?(?<!/)>
它与您的类似,但最后一个>不能在斜杠之后,也接受h1。
如果您只需要标记名,那么应该可以通过正则表达式执行此操作。
<([a-zA-Z]+)(?:[^>]*[^/] *)?>
应该做你需要的事。但我认为“莫里茨”的解决方案已经很好了。我一开始没看到。
对于所有反对者:在某些情况下,使用正则表达式是有意义的,因为这可能是最简单、最快捷的解决方案。我同意一般情况下不应该用正则表达式解析HTML。
但是当你有一个HTML子集,你知道格式并且你只想提取一些值时,正则表达式可以是一个非常强大的工具。我这样做了数百次,几乎总是达到我想要的目的。
<([a-z][^>\s]*)(?:\s+[^>]+)?>
此正则表达式将匹配由单个单词(例如<p>、<a>等)组成的开头标记,后跟零个或多个空格和任意数量的字符(除了>或空白),然后是结束>字符。它还会将标记与属性匹配,并且不会将标记与包含a-z以外字符的名称匹配。然而,它仍然不会匹配自动关闭标签。
如果PHP需要此功能:
除非是正确格式化的XML,否则PHP DOM函数将无法正常工作。不管它们对人类其他人的用处有多大。
simplehtmldom很好,但我发现它有点bug,而且内存很重[会在大页面上崩溃。]
我从未使用过querypath,所以不能评论它的有用性。
另一个可以尝试的是我的DOMParser,它非常节省资源,我已经很高兴地使用了一段时间。简单易学,功能强大。
对于Python和Java,发布了类似的链接。
对于反对者,我只在XML解析器无法承受实际使用时才编写了我的课程。宗教上的反对投票只是阻止了有用的答案被发布——请把事情放在问题的角度之内。
OP似乎没有说他需要用标签做什么。例如,他需要提取内部文本,还是只检查标签?
我坚定地认为正则表达式不是万能的文本解析器。我已经编写了大量的文本解析代码,包括用于解析HTML标记的代码。
虽然我确实对正则表达式不太在行,但我认为正则表达式太死板,很难维护这种解析。