diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs index 69511af80983bd..eaf5f23d3c639f 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs @@ -1000,8 +1000,9 @@ private RegexNode ScanReplacement() --_pos; nodeType = RegexNodeKind.Group; - // Disallow options in the children of a testgroup node - if (_group!.Kind != RegexNodeKind.ExpressionConditional) + // While parsing the test of a conditional (ExpressionConditional with no children yet), + // disallow inline options; allow them once the test has been parsed and in the yes/no branches. + if (_group!.Kind != RegexNodeKind.ExpressionConditional || _group.ChildCount() > 0) { ScanOptions(); } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs index c03f22a893ac1a..0a5e4e4d7e6fe5 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs @@ -898,6 +898,16 @@ public static IEnumerable Match_MemberData() yield return (@"(?(\w+)\w+)dog", "catdog", RegexOptions.None, 0, 6, true, "catdog"); yield return (@"(?(abc)\w+|\w{0,2})dog", "catdog", RegexOptions.None, 0, 6, true, "atdog"); yield return (@"(?(abc)cat|\w{0,2})dog", "catdog", RegexOptions.None, 0, 6, true, "atdog"); + + // Inline options inside conditional branches + yield return (@"(?(cat)(?i)CAT|dog)", "cat", RegexOptions.None, 0, 3, true, "cat"); + yield return (@"(?(cat)(?i)cat|dog)", "dog", RegexOptions.None, 0, 3, true, "dog"); + yield return (@"(?(cat)cat|(?i)dog)", "DOG", RegexOptions.None, 0, 3, true, "DOG"); + yield return (@"(?(cat)(?i:CAT)|dog)", "cat", RegexOptions.None, 0, 3, true, "cat"); + yield return (@"(?(?=cat)(?i)CAT|dog)", "cat", RegexOptions.None, 0, 3, true, "cat"); + yield return (@"(cat)?(?(1)(?i)dog|pig)", "catDOG", RegexOptions.None, 0, 6, true, "catDOG"); + yield return (@"(cat)?(?(1)(?i)dog|pig)", "pig", RegexOptions.None, 0, 3, true, "pig"); + yield return (@"(?((?i)cat)CAT|dog)", "CAT", RegexOptions.None, 0, 3, true, "CAT"); yield return ("(a|ab|abc|abcd)d", "abcd", RegexOptions.RightToLeft, 0, 4, true, "abcd"); yield return ("(?>(?:a|ab|abc|abcd))d", "abcd", RegexOptions.None, 0, 4, false, string.Empty); diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexParserTests.netcoreapp.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexParserTests.netcoreapp.cs index a3e02e8439e2a9..06e157a7587659 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexParserTests.netcoreapp.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexParserTests.netcoreapp.cs @@ -26,6 +26,7 @@ public partial class RegexParserTests [InlineData(@"(?(?X))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)] [InlineData(@"(?(?n))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)] [InlineData(@"(?(?m))", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)] + [InlineData(@"(?(?i)yes|no)", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 5)] // does not throw on .NET Framework, but that is a parser bug there [InlineData("(?<-", RegexOptions.None, RegexParseError.InvalidGroupingConstruct, 3)] [InlineData("(?<-", RegexOptions.IgnorePatternWhitespace, RegexParseError.InvalidGroupingConstruct, 3)] [InlineData(@"^[^<>]*(((?'Open'<)[^<>]*)+((?'Close-Open'>)[^<>]*)+)*(?(Open)(?!))$", RegexOptions.None, null)]