在非捕获组内递归捕获组?

时间:2015-06-23 11:45:07

标签: .net regex

所以我得到了以下输入:1,6-10,10000,2,10-11

以下正则表达式:.NET正则表达式中的^\d+(?:,(\d+|\d+-\d+))*$

我想匹配逗号之间的每个组,但我也希望捕获组最终如下:

Group 1: 1
Group 2: 6-10
Group 3: 10000
Group 4: 2
Group 5: 10-11

我尝试过使用任何非捕获组和其他捕获组的组合,但我无法找到解决方案。我错过了什么?

1 个答案:

答案 0 :(得分:2)

.net正则表达式实现提供了存储重复捕获组的子串的可能性。因此,使用此模式描述整个字符串:

\A(?:(\d+(?:-\d+)?)(?:,|\z))+\z

(其中\A\z代表字符串的开头和结尾)您只需一次匹配即可获取捕获组1中的所有值:{{ 3}}

这样可以确保整个字符串从开头到结尾的格式正确。

代码示例:

string input = "1,6-10,10000,2,10-11";
string pattern = @"\A(?:(\d+(?:-\d+)?)(?:,|\z))+\z";
Match match = Regex.Match(input, pattern);
if (match.Success) {
    Console.WriteLine("Matched text: {0}", match.Value);
    for (int ctr = 1; ctr < match.Groups.Count; ctr++) {
        Console.WriteLine(" Group {0}:  {1}", ctr, match.Groups[ctr].Value);
        int captureCtr = 0;
        foreach (Capture capture in match.Groups[ctr].Captures) {
             Console.WriteLine("   Capture {0}: {1}", captureCtr, capture.Value);
             captureCtr++; 
        }
    }
}

另一种方法是使用全局研究(几次连续匹配)并确保所有结果都是连续的。为此,您需要使用\G锚点构建一个模式,该模式匹配上一个匹配后位置字符串的开头:demo

\G(\d+(?:-\d+)?)(?:(,)|\z)

为确保已达到字符串的结尾,您只需检查第二个捕获组在上一次匹配时是否为空。

代码示例:

string input = "1,6-10,10000,2,10-11";

string pattern = @"\G(\d+(?:-\d+)?)(?:(,)|\z)";

MatchCollection results = Regex.Matches(input, pattern);

if (results.Count == 0) {
    Console.WriteLine("No results");
} else if ( results[results.Count - 1].Groups[2].Length > 0 ) {
    Console.WriteLine("Bad format");
} else {
    foreach (Match match in results) {
        Console.WriteLine(match.Groups[1]);
    }
}

显然,如果你已经知道你的字符串格式正确,这两种方法都是无用的,只需用逗号进行简单的拆分即可获得结果。