在C#正则表达式中,为什么初始匹配会显示在组中?

因此,如果我写一个正则表达式匹配我可以得到匹配或我可以访问其组。 这似乎是反直觉的,因为组在表达式中用大括号“(”和“)”定义。 看起来它不仅错误而且多余。 谁知道为什么?

Regex quickCheck = new Regex(@"(\D+)\d+"); string source = "abc123"; m.Value //Equals source m.Groups.Count //Equals 2 m.Groups[0]) //Equals source m.Groups[1]) //Equals "abc" 

我同意 – 这有点奇怪,但我认为有充分的理由。

正则表达式Match本身就是一个Group ,而后者又是一个组。

Match.Value (或实际上的Capture.Value )仅在字符串中存在一个匹配时才有效 – 如果您匹配模式的多个实例,则根据定义它不能返回所有内容。 实际上 – 匹配时的Value属性是仅在匹配时的便利。

但是要澄清将整个匹配传递给Groups[0]行为在哪里是有意义的 – 考虑一个天真的代码unminifier的这个(人为的)示例:

 [TestMethod] public void UnMinifyExample() { string toUnMinify = "{int somevalue = 0; /*init the value*/} /* end */"; string result = Regex.Replace(toUnMinify, @"(;|})\s*(/\*[^*]*?\*/)?\s*", "$0\n"); Assert.AreEqual("{int somevalue = 0; /*init the value*/\n} /* end */\n", result); } 

正则表达式匹配将在语句结束时保留/ * * / comments,之后放置换行符 – 但适用于任何一个; 或}行结尾。

好吧 – 你可能想知道为什么你会用正则表达式来做这件事 – 但是幽默我:)

如果由此正则表达式的匹配生成的Groups[0]不是整个捕获 – 则单个调用替换将不可能 – 并且您的问题可能会问为什么整个匹配不会被放入Groups[0]而不是反过来!

Match的文档说第一组始终是整个匹配,因此它不是实现细节。

这是历史的全部。 在Perl 5中,捕获组的内容存储在特殊变量$1$2等中,但是C#,Java和其他人将它们存储在一个数组(或类似数组的结构)中。 为了保持与Perl的命名约定(已被其他几种语言复制)的兼容性,第一组存储在元素1中,第二组存储在元素2中,等等。这使得元素零自由,所以为什么不在那里存储完整的匹配?

仅供参考,Perl 6采用了一项新惯例,其中第一个捕获组编号为零而不是一个。 我敢肯定,只是为了惹恼我们。 ;)

不确定为什么,但如果使用命名组,则可以设置RegExOptions.ExplicitCapture选项,并且不应将源包含为第一组。

最有可能的是,您可以使用“$ 0”表示替换表达式中的匹配,并使用“$ 1”表示第一组匹配等。

我不认为除了写这篇文章的人选择这个作为实现细节之外,确实有一个答案。 只要你记得第一组总是等于源字符串你应该没问题:-)

它可能是多余的,但它有一些不错的属性。

例如,它意味着捕获组的工作方式与其他正则表达式引擎相同 – 第一个捕获组对应于“1”,依此类推。

反向引用是基于一的, 例如\1$1是第一个带括号的子表达式,依此类推。 如图所示,一个人没有任何想法映射到另一个。

另外值得注意的是: m.Groups["0"]为您提供了整个匹配的子字符串,因此如果您在regex.GetGroupNames()迭代, regex.GetGroupNames()务必跳过"0"