为什么这个循环通过正则表达式组打印输出两次

本文关键字:输出 两次 打印 循环 正则表达式 为什么 | 更新日期: 2023-09-27 18:24:17

我写了这个非常简单的正则表达式代码

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);
                }
            }
        }
    }
}

但是输出是

0"福吧123=="1福吧123==

我不明白为什么它打印两次。 为什么应该在索引 0 处进行捕获? 当我在我的正则表达式^'"中说并且我没有为此使用捕获时。

抱歉,如果这是非常基本的,但我不会每天编写正则表达式。

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

为什么这个循环通过正则表达式组打印输出两次

发生这种情况是因为组 0 很特殊:它返回整个匹配项。

来自正则表达式文档(强调添加(:

一个简单的正则

表达式模式说明了如何以编程方式或使用正则表达式语言语法引用编号(未命名(和命名组。正则表达式((?<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)

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

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

假设您的正则表达式具有以下形式:

A(B(C)D)E.

使用ABCD结束E正则表达式。

然后,将匹配以下组:

0 A(B(C)D)E
1 B(C)D
2 C

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);
                }
            }
        }
    }
}
0
"foobar123=="  --  Matched string. 

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

1
foobar123==     -- Captured string. 

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

以@dasblinkenlight正则表达式为例...

这并不是 Dot-Net 捕获组计数的全部故事。添加命名组时,默认值为计数它们并最后计数。可以选择更改这些内容。

当然,组 0 始终包含整个匹配项。组计数实际上从 1
开始由于无法指定对组 0 的反向引用(在正则表达式中(,因此会冲突
使用二进制构造'0000 .

这是在 Dot-Net 默认状态下使用命名/普通组进行计数。

 (                                  # (1 start)
      (?<One> abc )                 #_(3)         
      'd+ 
 )?                                 # (1 end)
 (?<Two> xyz )                      #_(4)         
 ( .* )                             # (2)

这是最后关闭的名称。

 (                                  # (1 start)
      (?<One> abc )                 # (2)
      'd+ 
 )?                                 # (1 end)
 (?<Two> xyz )                      # (3)
 ( .* )                             # (4)

这是关闭命名计数。

 (                                  # (1 start)
      (?<One> abc )
      'd+ 
 )?                                 # (1 end)
 (?<Two> xyz )
 ( .* )                             # (2)

通过使用 ?: 删除组 1 来仅返回一个

 Regex r = new Regex("^'"(?:.*)'"$");

在线演示

每次使用()创建组时,以后可以使用反向引用引用它们 $1,$2,$3 当然,在您的表达式的情况下更简单:

Regex r = new Regex("^'".*'"$");

根本不使用括号