对于.NET的正则表达式语言,“组”和“捕获”之间的区别让我有些模糊。考虑以下C#代码:
MatchCollection matches = Regex.Matches("{Q}", @"^\{([A-Z])\}$");
我希望这会导致字母'Q'的单个捕获,但是如果我打印返回的
MatchCollection
的属性,则会看到:matches.Count: 1
matches[0].Value: {Q}
matches[0].Captures.Count: 1
matches[0].Captures[0].Value: {Q}
matches[0].Groups.Count: 2
matches[0].Groups[0].Value: {Q}
matches[0].Groups[0].Captures.Count: 1
matches[0].Groups[0].Captures[0].Value: {Q}
matches[0].Groups[1].Value: Q
matches[0].Groups[1].Captures.Count: 1
matches[0].Groups[1].Captures[0].Value: Q
这到底是怎么回事?我知道整个比赛也都有机会,但是小组如何进入?为什么
matches[0].Captures
不包含字母'Q'的捕获? 最佳答案
您不会是第一个对此感到困惑的人。这就是著名的Jeffrey Friedl关于它的说法(第437+页):
进一步:
几页后,这就是他的结论:
换句话说:它们非常相似,但是偶尔会碰巧有它们的用处。在长出另一头灰色 mustache 之前,您甚至可能喜欢Captures ...
由于以上内容或其他帖子中的内容都无法真正回答您的问题,请考虑以下内容。将Captures视为一种历史跟踪器。当正则表达式匹配时,它从左到右遍历字符串(暂时忽略回溯),当遇到匹配的捕获括号时,它将把它存储在$x
(x是任何数字)中,比如$1
。
普通的正则表达式引擎,当要重复捕获括号时,将丢弃当前的$1
并将其替换为新值。不是.NET,它将保留此历史记录并将其放置在Captures[0]
中。
如果我们将您的正则表达式更改为如下所示:
MatchCollection matches = Regex.Matches("{Q}{R}{S}", @"(\{[A-Z]\})+");
您会注意到,第一个
Group
将具有一个Captures
(第一个组始终是整个匹配项,即等于$0
),第二个组将保留{S}
,即仅最后一个匹配组。但是,这是渔获物,如果要查找其他两个渔获物,它们都在Captures
中,其中包含{Q}
{R}
和{S}
的所有中间捕获。如果您想知道如何从多重捕获(仅显示最后一个匹配项与字符串中明显存在的单个捕获项)中得到的结果,则必须使用
Captures
。关于您的最后一个问题的最后一句话:总匹配始终具有总捕获,请勿将其与各个组混合使用。捕获仅在组内部有趣。