Regex patterns with ranges corrected

Regex incorrectly handles the casing of some ranges in .NET Framework, and in .NET 6 and earlier versions. This bug was fixed in .NET 7.

The fix for this bug could cause a breaking change if your regular expression has a bug that was hidden because of this bug or if you implemented a workaround for this bug.

Previous behavior

In .NET 6 and earlier versions, the following two patterns produce different results. However, they should produce the same result (false), since the range \xD7-\xD8 only includes the values \xD7 and \xD8 themselves.

// Evaluates to false.
Regex.IsMatch("\xF7", @"^(?i:[\xD7\xD8])$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
// Evaluates to true.
Regex.IsMatch("\xF7", @"^(?i:[\xD7-\xD8])$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

New behavior

Starting in .NET 7, the example patterns both evaluate to false.

// Evaluates to false.
Regex.IsMatch("\xF7", @"^(?i:[\xD7\xD8])$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
// Evaluates to false.
Regex.IsMatch("\xF7", @"^(?i:[\xD7-\xD8])$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

Version introduced

.NET 7

Type of breaking change

This change is a behavioral change.

Reason for change

The previous behavior was incorrect.

If your regular expression has a hidden bug, fix it. If you had a workaround for this bug, you can remove the workaround.

Affected APIs