【发布时间】:2011-04-13 12:56:18
【问题描述】:
作为针对此问题的一般酿造示例,我的意图是匹配一些a,然后匹配相同数量的b,再加上一个b。
检查此 sn-p (also on ideone.com) 中展示的两种模式:
var r1 = new Regex(@"(?xn)
(?<A> a)+ (?<B-A> b)+ (?(A)(?!)) b
");
var r2 = new Regex(@"(?xn)
(?<A> a)+ (?<B-A> b)+? (?(A)(?!)) b
");
Console.WriteLine(r1.Match("aaabbb"));
// aaabbb
Console.WriteLine(r2.Match("aaabbb"));
// aabbb
请注意,两种模式的匹配存在差异。 r1,在平衡组构造上使用贪婪重复,匹配 3 个a 和 3 个b,这 NOT 符合预期。 r2,使用不情愿的重复,给了我 2 个a 和 3 个b,这 IS 符合预期。
我可以解释这一点的唯一方法是,当(?<B-A> b)+ 回溯以匹配少一个b 时,它会从B 堆栈中弹出,但不会推回相应弹出的内容A 堆栈。因此,即使由于回溯,现在匹配少一个b,A 堆栈仍然是空的。这是我可以解释r1如何匹配aaabbb的唯一方法。
请注意,在r2 中使用不情愿的+? 不会导致此问题。在我看来,这是因为与贪婪的重复不同,不情愿的重复不必“消除对A 堆栈的损害”,可以这么说。相比之下,贪婪的重复会造成尽可能多的“损害”,但回溯无法“让事情保持原样”到A 堆栈。
这是对所发生事件的正确分析吗?如果是这样,这种行为是设计使然吗?因为在我看来基本上是在贪婪的重复中回溯平衡组可能会导致不平衡,因此这可能被归类为错误(或至少是没有充分记录的有点令人惊讶的行为)。
【问题讨论】:
-
我无法重现您的观察结果。我将您的代码直接粘贴到 Visual Studio 中,它按预期输出两次
aabbb。 -
也适合我。我正在使用 .NET 框架的 4.0 版。
-
@Jens, @Timwi:你知道我可以粘贴我的 C# sn-p 并让它针对各种版本的 .NET 框架运行的其他在线应用程序吗?因为很明显 ideone.com 上的那个给出了不同的输出。
-
RegExLib.com (regexlib.com/RETester.aspx)
-
“令人惊讶的行为”是正则表达式被用于显然是一种非常规的上下文无关语言:-)
标签: c# .net regex backtracking balancing-groups