diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 10ec814bea2649..4d31cf5715342c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -1832,6 +1832,16 @@ static bool CanCombineCounts(int nodeMin, int nodeMax, int nextMin, int nextMax) currentNode.MakeRep(RegexNodeKind.Oneloop, 2, 2); next++; continue; + + // Coalescing identical anchors (e.g. \b\b). These don't need to become loops, as they collapse to a single anchor. + case RegexNodeKind.Beginning or RegexNodeKind.Start or + RegexNodeKind.End or RegexNodeKind.EndZ or + RegexNodeKind.Bol or RegexNodeKind.Eol or + RegexNodeKind.Boundary or RegexNodeKind.NonBoundary or + RegexNodeKind.ECMABoundary or RegexNodeKind.NonECMABoundary + when nextNode.Kind == currentNode.Kind: + next++; + continue; } } diff --git a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexReductionTests.cs index 31967fb8d965b8..0211065fbb8051 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/RegexReductionTests.cs @@ -376,6 +376,16 @@ public class RegexReductionTests [InlineData("(abc?)*?d", "(ab(?>c?))*?d")] [InlineData("(ab*c)*d", "(?>(a(?>b*)c)*)d")] [InlineData("(aba)?d", "(?>(aba)?)d")] + // Anchors + [InlineData(@"\b\b", @"\b")] + [InlineData(@"\b\b\b\b\b", @"\b")] + [InlineData(@"\B\B", @"\B")] + [InlineData(@"^^", @"^")] + [InlineData(@"$", @"$")] + [InlineData(@"\Z\Z", @"\Z")] + [InlineData(@"\z\z", @"\z")] + [InlineData(@"\G\G", @"\G")] + [InlineData(@"\A\A", @"\A")] // Nothing handling [InlineData(@"\wabc(?!)def", "(?!)")] [InlineData(@"\wabc(?!)def|ghi(?!)", "(?!)")] @@ -532,6 +542,10 @@ public void PatternsReduceIdentically(string actual, string expected) [InlineData("a*(?(xyz)bcd)", "(?>a*)(?(xyz)bcd)")] // Different prefixes on alternation branches [InlineData("^abcd|$abce", "^abcd|^abce")] + // Anchors + [InlineData(@"\b\B", "\b")] + [InlineData(@"^$", "^")] + [InlineData(@"^$", "$")] public void PatternsReduceDifferently(string actual, string expected) { // NOTE: RegexNode.ToString is only compiled into debug builds, so DEBUG is currently set on the unit tests project.