为什么循环通过Regex组打印输出两次?

Kno*_*uch 14 c# regex

我写了这个非常直接的正则表达式代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace RegexTest1
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "\"foobar123==\"";
            Regex r = new Regex("^\"(.*)\"$");
            Match m = r.Match(a);
            if (m.Success)
            {
                foreach (Group g in m.Groups)
                {
                    Console.WriteLine(g.Index);
                    Console.WriteLine(g.Value);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但输出是

0
"foobar123=="
1
foobar123==

我不明白为什么它打印两次.为什么在指数0处有一个捕获?当我在我的正则表达式中说,我^\"没有使用捕获.

很抱歉,如果这是非常基本的,但我不会每天写Regex.

据我说,这段代码应该只打印一次,索引应该是1,值应该是foobar ==

das*_*ght 23

发生这种情况是因为组零是特殊的:它返回整个匹配.

Regex文档(重点添加):

一个简单的正则表达式模式说明了如何以编程方式或使用正则表达式语言语法引用编号(未命名)和命名组.正则表达式((?<One>abc)\d+)?(?<Two>xyz)(.*)按编号和名称生成以下捕获组.第一个捕获组(编号0)始终指整个模式.

#      Name              Group
- ---------------- --------------------------------
0 0 (default name) ((?<One>abc)\d+)?(?<Two>xyz)(.*)

1 1 (default name) ((?<One>abc)\d+)

2 2 (default name) (.*)

3 One (?<One>abc)

4 Two (?<Two>xyz)
Run Code Online (Sandbox Code Playgroud)

如果您不想看到它,请从第一组开始输出.


Wil*_*sem 13

正则表达式一次捕获几个组.组0是整个匹配区域(包括重音符号).组1是由括号定义的组.

说你的正则表达式有以下形式:

A(B(C)D)E.
Run Code Online (Sandbox Code Playgroud)

随着A,B,C,D结束E正则表达式的表达式.

然后将匹配以下组:

0 A(B(C)D)E
1 B(C)D
2 C
Run Code Online (Sandbox Code Playgroud)

i个小组开始在i个开括号.你可以说"零"开放括号隐式放在正则表达式的开头(并在正则表达式的末尾结束).

如果要省略组0,可以使用LINQ框架的Skip方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace RegexTest1 {
    class Program {
        static void Main(string[] args) {
            string a = "\"foobar123==\"";
            Regex r = new Regex("^\"(.*)\"$");
            Match m = r.Match(a);
            if (m.Success) {
                foreach (Group g in m.Groups.Skip(1)) {//Skipping the first (thus group 0)
                    Console.WriteLine(g.Index);
                    Console.WriteLine(g.Value);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这可能不是Dot-Net捕获组计数的全部故事.当添加命名组时,默认值是对它们进行计数并最后计算它们.这些可以任意改变.像"A(?<B> B(C)D)E"这样的计数默认值并不是你所期望的. (2认同)

Avi*_*Raj 5

0
"foobar123=="  --  Matched string. 
Run Code Online (Sandbox Code Playgroud)

按模式的整个匹配将在索引0处找到.

1
foobar123==     -- Captured string. 
Run Code Online (Sandbox Code Playgroud)

组索引1包含第一个捕获组捕获的字符.

  • 也许一些解释是合适的? (3认同)

小智 5

使用@dasblinkenlight正则表达式作为示例...

这不是Dot-Net捕获组计数的全部故事.添加命名组时,默认值会计算它们并最后计算它们.这些可以任意改变.

当然,组0总是包含整个匹配.组计数实际上从1开始,
因为你不能指定后向引用(在正则表达式中)到组0,它
二进制构造冲突\0000.

这里计数Dot-Net中的命名/普通组是默认状态.

 (                                  # (1 start)
      (?<One> abc )                 #_(3)         
      \d+ 
 )?                                 # (1 end)
 (?<Two> xyz )                      #_(4)         
 ( .* )                             # (2)
Run Code Online (Sandbox Code Playgroud)

这里是名字最后关闭.

 (                                  # (1 start)
      (?<One> abc )                 # (2)
      \d+ 
 )?                                 # (1 end)
 (?<Two> xyz )                      # (3)
 ( .* )                             # (4)
Run Code Online (Sandbox Code Playgroud)

这里是命名计数关闭.

 (                                  # (1 start)
      (?<One> abc )
      \d+ 
 )?                                 # (1 end)
 (?<Two> xyz )
 ( .* )                             # (2)
Run Code Online (Sandbox Code Playgroud)