最近,我发现一个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只返回最后一个匹配的字符串?这种设计看起来不太好。
答案 0 :(得分:2)
主要原因是历史:正则表达式一直以这种方式工作,回到Perl及以后。但它的设计并不是很糟糕。通常情况下,如果你想要这样的每一场比赛,你只需要离开最外面的量词(在这种情况下为+
)并使用Matches()
方法而不是Match()
。每个启用正则表达式的语言都提供了一种方法:在Perl或JavaScript中,您可以在/g
模式下进行匹配;在Ruby中,您使用scan
方法;在Java中,您反复调用find()
,直到它返回false
。同样,如果您正在执行替换操作,则可以在使用占位符($1
,$2
或\1
,\2
时依次插入捕获的子字符串,具体取决于关于语言)。
另一方面,我知道没有其他Perl 5派生的正则表达式风格能够检索中间捕获组匹配,如.NET与CaptureCollections。而且我并不感到惊讶:实际上很少你真的需要一次性捕捉所有的比赛。并考虑所有存储和/或处理能力,以跟踪所有这些中间匹配。这是一个很好的功能。