在捕获组
捕获组尝试捕获它匹配的内容。这有一些重要的后果:
- 一个不匹配的群体,永远无法捕获任何东西。
- 只匹配空字符串的组,只能捕获空字符串。
- 在匹配尝试中重复捕获的组只能保留最后一次捕获
- 对于大多数风格来说通常是正确的,但 .NET 正则表达式是一个例外(请参阅相关问题)
这是一个包含 2 个捕获组的简单模式:
(\d+) (cats|dogs)
\___/ \_________/
1 2
给定 i have 16 cats, 20 dogs, and 13 turtles
,有 2 个匹配项(如 rubular.com 上所见):
16 cats
是一场比赛:第 1 组捕获16
,第 2 组捕获cats
20 dogs
是一场比赛:第 1 组捕获20
,第 2 组捕获dogs
现在考虑对模式的这种轻微修改:
(\d)+ (cats|dogs)
\__/ \_________/
1 2
现在第 1 组匹配\d
,即单个数字。在大多数情况下,重复匹配的组(感谢+
在这种情况下)只能保留最后一次匹配。因此,在大多数情况下,只有最后一个匹配的数字被第 1 组捕获(如在 rubular.com 上看到的):
16 cats
是一场比赛:第 1 组捕获6
,第 2 组捕获cats
20 dogs
是一场比赛:第 1 组捕获0
,第 2 组捕获dogs
参考
关于贪婪 vs 不情愿 vs 否定字符类
现在让我们考虑匹配“和之间的一切”的A
问题ZZ
。事实证明,这个规范是模棱两可的:我们将提出 3 种模式来做到这一点,它们会产生不同的匹配。哪一个是“正确的”取决于期望,这在原始陈述中没有正确传达。
我们使用以下内容作为输入:
eeAiiZooAuuZZeeeZZfff
我们使用 3 种不同的模式:
这是他们匹配的视觉表示:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
有关这三种技术之间差异的更深入处理,请参阅相关问题。
相关问题
回到问题
那么让我们回到这个问题,看看模式有什么问题:
<h1>()<br
\/
1
第 1 组匹配空字符串,因此整个模式整体只能匹配<hr1><br
,第 1 组只能匹配空字符串。
人们可以尝试以多种不同的方式“解决”这个问题。3个明显的尝试是:
<h1>(.*)<br
; 贪婪的
<h1>(.*?)<br
; 不情愿的
<h1>([^<]*)<br
; 否定字符类
你会发现以上所有的“工作”都不是一直有效的;一些 HTML 会有问题。这是意料之中的:正则表达式是这项工作的“错误”工具。您可以尝试使模式变得越来越复杂,以使其“正确”更频繁,而“错误”更少。很有可能你最终会遇到一个没有人能够理解和/或维护的可怕的混乱,而且它仍然可能不会在 100% 的时间里“正确”工作。