0

最近,我发现一个 C# Regex API 真的很烦人。

我有正则表达式(([0-9]+)|([a-z]+))+。我想找到所有匹配的字符串。代码如下所示。

string regularExp = "(([0-9]+)|([a-z]+))+";
string str = "abc123xyz456defFOO";

Match match = Regex.Match(str, regularExp, RegexOptions.None);
int matchCount = 0;

while (match.Success)
{
    Console.WriteLine("Match" + (++matchCount));

    Console.WriteLine("Match group count = {0}", match.Groups.Count);
    for (int i = 0; i < match.Groups.Count; i++)
    {
        Group group = match.Groups[i];
        Console.WriteLine("Group" + i + "='" + group.Value + "'");
    }

    match = match.NextMatch();
    Console.WriteLine("go to next match");
    Console.WriteLine();
}

输出是:

Match1
Match group count = 4
Group0='abc123xyz456def'
Group1='def'
Group2='456'
Group3='def'
go to next match

似乎所有 group.Value 都是最后一个匹配的字符串(“def”和“456”)。我花了一些时间弄清楚我应该依靠 group.Captures 而不是 group.Value。

string regularExp = "(([0-9]+)|([a-z]+))+";
string str = "abc123xyz456def";
//Console.WriteLine(str);

Match match = Regex.Match(str, regularExp, RegexOptions.None);
int matchCount = 0;

while (match.Success)
{
    Console.WriteLine("Match" + (++matchCount));

    Console.WriteLine("Match group count = {0}", match.Groups.Count);
    for (int i = 0; i < match.Groups.Count; i++)
    {
        Group group = match.Groups[i];
        Console.WriteLine("Group" + i + "='" + group.Value + "'");

        CaptureCollection cc = group.Captures;
        for (int j = 0; j < cc.Count; j++)
        {
            Capture c = cc[j];
            System.Console.WriteLine("    Capture" + j + "='" + c + "', Position=" + c.Index);
        }
    }

    match = match.NextMatch();
    Console.WriteLine("go to next match");
    Console.WriteLine();
}

这将输出:

Match1
Match group count = 4
Group0='abc123xyz456def'
    Capture0='abc123xyz456def', Position=0
Group1='def'
    Capture0='abc', Position=0
    Capture1='123', Position=3
    Capture2='xyz', Position=6
    Capture3='456', Position=9
    Capture4='def', Position=12
Group2='456'
    Capture0='123', Position=3
    Capture1='456', Position=9
Group3='def'
    Capture0='abc', Position=0
    Capture1='xyz', Position=6
    Capture2='def', Position=12
go to next match

现在,我想知道为什么 API 设计是这样的。为什么 Group.Value 只返回最后一个匹配的字符串?这个设计看起来不太好。

4

1 回答 1

2

主要原因是历史性的:正则表达式一直都是这样工作的,可以追溯到 Perl 及其他版本。但这并不是一个糟糕的设计。通常,如果你想要这样的每一个匹配,你只需去掉最外层的量词(+在这种情况下)并使用Matches()方法而不是Match(). 每种启用正则表达式的语言都提供了一种方法来做到这一点:在 Perl 或 JavaScript 中,您可以在/g模式下进行匹配;在 Ruby 中,您使用该scan方法;在 Java 中,您find()反复调用直到它返回false。同样,如果您正在执行替换操作,则可以在使用占位符($1,$2\1, \2,具体取决于语言)时将捕获的子字符串重新插入。

另一方面,我知道没有其他 Perl 5 派生的正则表达式能够提供检索中间捕获组匹配的能力,就像 .NET 使用其 CaptureCollections 所做的那样。我并不感到惊讶:实际上很少需要像这样一次性捕获所有比赛。想想跟踪所有这些中间匹配可能需要的所有存储和/或处理能力。这是一个不错的功能。

于 2009-12-18T05:40:33.930 回答