diff --git a/src/libraries/Common/src/System/Number.Parsing.Common.cs b/src/libraries/Common/src/System/Number.Parsing.Common.cs index e43cbe14c29226..38d08e97a86e41 100644 --- a/src/libraries/Common/src/System/Number.Parsing.Common.cs +++ b/src/libraries/Common/src/System/Number.Parsing.Common.cs @@ -345,14 +345,16 @@ internal enum ParsingStatus if (TChar.CastToUInt32(*str) != '\0') { // We only hurt the failure case - // This fix is for French or Kazakh cultures. Since a user cannot type 0xA0 or 0x202F as a - // space character we use 0x20 space character instead to mean the same. + // This fix is for cultures that use NBSP (U+00A0) or narrow NBSP (U+202F) as group/decimal separators + // (e.g., French, Kazakh, Ukrainian). Since a user cannot easily type these characters, + // we accept regular space (U+0020) as equivalent. + // We also need to handle the reverse case where the input has NBSP and the format string has space. while (true) { uint cp = (p < pEnd) ? TChar.CastToUInt32(*p) : '\0'; uint val = TChar.CastToUInt32(*str); - if ((cp != val) && !(IsSpaceReplacingChar(val) && (cp == '\u0020'))) + if ((cp != val) && !(((cp == '\u0020') && IsSpaceReplacingChar(val)) || ((val == '\u0020') && IsSpaceReplacingChar(cp)))) { break; } diff --git a/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs b/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs index bdfde88395a326..8b648ae2432302 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs @@ -1331,6 +1331,26 @@ private static void Eval(BigInteger x, string expected) } Assert.Equal(expected, actual); } + + [Fact] + public static void ParseWithNBSPAsGroupSeparator() + { + // Create a custom culture with NBSP as NumberGroupSeparator + // This tests the bidirectional space equivalence fix without depending on + // specific culture data that may vary across systems/ICU versions + CultureInfo ci = new CultureInfo("en-US"); + ci.NumberFormat.NumberGroupSeparator = "\u00A0"; + + // Test that regular space is accepted as equivalent to NBSP when culture uses NBSP + string testWithSpace = "1 234 567"; // Regular spaces used as thousands separators + BigInteger result = BigInteger.Parse(testWithSpace, NumberStyles.AllowThousands, ci); + Assert.Equal(BigInteger.Parse("1234567"), result); + + // Test with trailing space + string testWithTrailingSpace = "123 "; + result = BigInteger.Parse(testWithTrailingSpace, NumberStyles.AllowTrailingWhite, ci); + Assert.Equal(BigInteger.Parse("123"), result); + } } [Collection(nameof(DisableParallelization))]