【问题标题】:C# Regular expression returns group multiple timesC#正则表达式多次返回组
【发布时间】:2014-03-03 19:10:33
【问题描述】:

我在 C# 中有一个像这样的非常简单的正则表达式:

(var \= 0\;)

但是当我尝试将其与仅出现一次模式的字符串进行匹配时,我会返回多个组。输入字符串为:

foo bar
var = 0;
foo

我得到 Regex 对象返回的 1 个匹配项,但在里面我看到两个组,每个组都有 1 个捕获,这是我想要的字符串。 我需要正则表达式中的分组括号,因为这是更大的正则表达式的一部分,我需要将其作为一个组捕获。 我做错了什么?

编辑

这是我正在使用的 C# 代码:

private const string REGEX = "(var \\= [0]\\;)";
MatchCollection matches = REGEX.Matches(inputStr);
foreach (Match m in matches)
{
    foreach (Group g in m.Groups)
    {
        Console.WriteLine("group[" + g.Captures.Count + "]: '" + g.ToString() + "'");
    }
}

这是我得到的:

group[1]: 'var = 0;'
group[1]: 'var = 0;'

我的问题是,为什么我得到两组而不是一组?

编辑#2:

更复杂的模式显示了问题。模式:

# preceding comment
class
{
   (param1 = "val1", param2 = "val2", param3 = val3)
}
[
    # inside comment
    setting1 = 0;
    setting2 = 0;
]

我正在使用的正则表达式:(它可能不是最明显的,但如果您想查看,可以将其粘贴到正则表达式查看器中)

(\#[^\n]*)?(?:[\s\r\n]*)domain(?:[\s\r\n]*)\{(?:[\s\r\n]*)\((?:[\s\r\n]*)(((?:[\s\r\n]*)(accountName(?:[\s\r\n]*)\=(?:[\s\r\n]*)\"[^"]+\"[,]?)(?:[\s\r\n]*))|((?:[\s\r\n]*)(tableName(?:[\s\r\n]*)\=(?:[\s\r\n]*)\"[^"]+\"[,]?)(?:[\s\r\n]*))|((?:[\s\r\n]*)(cap(?:[\s\r\n]*)\=(?:[\s\r\n]*)[\d]+[,]?)(?:[\s\r\n]*))|((?:[\s\r\n]*)(MinPartitionCount(?:[\s\r\n]*)\=(?:[\s\r\n]*)[\d]+[,]?)(?:[\s\r\n]*)))+\)(?:[\s\r\n]*)\}(?:[\s\r\n]*)\[(?:[\s\r\n]*)(\#[^\n]*)?(?:[\s\r\n]*)((?:[\s\r\n]*)(IsSplitEnabled(?:[\s\r\n]*)\=(?:[\s\r\n]*)[0|1](?:[\s\r\n]*)\;)(?:[\s\r\n]*)|(?:[\s\r\n]*)(IsMergeEnabled(?:[\s\r\n]*)\=(?:[\s\r\n]*)[0|1](?:[\s\r\n]*)\;)(?:[\s\r\n]*))*(?:[\s\r\n]*)\]

我得到:

group:1: '# preceding comment
domain
{
   (param1 = "val1", param2 = "val2", param3 = val3)
}
[
    # inside comment
    setting1 = 0;
    setting2 = 0;
]'
'roup:1: '# preceding comment
group:3: 'cap = 1200'
group:1: 'param1 = "val1", '
group:1: 'param1 = "val1",'
group:1: 'param2 = "val2", '
group:1: 'param2 = "val2",'
group:1: 'param3 = val3'
group:1: 'param3 = val3'
'roup:1: '# inside comment
group:2: 'setting1 = 0;
'
group:1: 'setting1 = 0;'
group:1: 'setting2 = 0;'

【问题讨论】:

  • 你能展示一个演示问题的最小 C# 示例吗?
  • 可能您的第一组用于整个表达式,而第二组用于您的正则表达式中明确的组?如果您命名您的捕获组会发生什么 - 两个组会显示相同的名称吗?例如(?<mygroup>var \= 0\;)
  • @LB2 如何在 C# 中打印组名?
  • @Yasser 我以为它有一个属性,但你是对的,没有一个(奇怪)。但 davisoa 的回答与我之前的评论基本相同——第一组是整个表达式,然后是子组。
  • 我是凭记忆写的,但是有一种方法可以检索组名列表。只需在 LINQPad 上测试您的代码并转储结果,以便您可以查看所有属性。

标签: c# regex


【解决方案1】:

根据文档,GroupCollection 的第一个元素是整个匹配,而不是() 创建的第一个组。

从备注部分底部附近here

如果正则表达式引擎可以找到匹配项,则第一个元素 Groups 属性返回的 GroupCollection 对象包含 匹配整个正则表达式模式的字符串。如果正则表达式包括捕获组,则每个后续元素 > 表示一个捕获组。

因此,鉴于您当前使用的 RegEx,项目 0 和 1 是相同的。要仅查看实际的组匹配,您可以跳过 GroupCollection 的第一个元素,并仅处理您在 RegEx 中定义的组。

编辑

在调查了额外的数据后,我想我可能已经找到了您重复的原因。

我相信您看到的Match 不止一个,因此外部foreach 循环运行了两次,而不是一次。这是因为有 2 行带有“= 0;”的单独行在示例中。

这里是 LinqPad 示例代码,显示找到了 2 个匹配项,因此输出了多个重复组。 (注意,我使用您提供的简单正则表达式进行测试,因为长正则表达式没有提供任何匹配项)

static string inputStr = "# preceding comment \r\n" + 
"class\r\n" + 
"{\r\n" + 
"   (param1 = \"val1\", param2 = \"val2\", param3 = val3)\r\n" + 
"}\r\n" + 
"[\r\n" + 
"    # inside comment\r\n" + 
"    setting1 = 0;\r\n" + 
"    setting2 = 0;\r\n" + 
"]\r\n";

const string REGEX = "(\\= [0]\\;)";

void Main()
{

    var regex = new System.Text.RegularExpressions.Regex(REGEX);
    MatchCollection matches = regex.Matches(inputStr);
    Console.WriteLine("Matches:{0}", matches.Count);
    int matchCnt = 0;
    foreach (Match m in matches)
    {
        int groupCnt = 0;
        foreach (Group g in m.Groups)
        {
            Console.WriteLine("match[{0}] group[{1}]: Captures:{2} '{3}'", matchCnt, groupCnt, g.Captures.Count, g);
            //g.Dump();
            groupCnt++;
        }
        matchCnt++;
    }
    Console.WriteLine("Done!");
}

这是代码运行时 LinqPad 生成的输出:

Matches:2
match[0] group[0]: Captures:1 '= 0;'
match[0] group[1]: Captures:1 '= 0;'
match[1] group[0]: Captures:1 '= 0;'
match[1] group[1]: Captures:1 '= 0;'
Done!

【讨论】:

  • 这有帮助,但是当我有一个较长的正则表达式时,问题就会出现,其中一些组会被多次返回。
  • 您能否发布一个示例,说明当您忽略 GroupCollection 中的第一个结果时,某些组多次返回时会发生这种情况?
  • 为您的群组命名,然后按名称查找群组将有助于解决此问题。编辑:LB2 在对该问题的评论中提出了同样的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多