diff --git a/PreciseNumber.Test/PreciseNumberParseCultureTests.cs b/PreciseNumber.Test/PreciseNumberParseCultureTests.cs index ac429ee..24e238b 100644 --- a/PreciseNumber.Test/PreciseNumberParseCultureTests.cs +++ b/PreciseNumber.Test/PreciseNumberParseCultureTests.cs @@ -241,4 +241,41 @@ public void Parse_RejectsATypedSpaceWhenTheStyleDoesNotAllowThousands() Assert.IsFalse(PreciseNumber.TryParse("1 234", NumberStyles.Float, NarrowSpaceGroups, out _)); Assert.IsFalse(PreciseNumber.TryParse("1 234", NumberStyles.Float, NoBreakSpaceGroups, out _)); } + + [TestMethod] + [DataRow("\u00A05", NumberStyles.Integer)] + [DataRow("5\u3000", NumberStyles.AllowTrailingWhite)] + [DataRow("\u00855", NumberStyles.Float)] + [DataRow("5\u2028", NumberStyles.Float)] + public void Parse_RejectsNonAsciiWhiteSpaceAroundTheNumber(string input, NumberStyles style) + { + Assert.IsFalse(decimal.TryParse(input, style, CultureInfo.InvariantCulture, out _), "The BCL should reject this input too."); + Assert.IsFalse(PreciseNumber.TryParse(input, style, CultureInfo.InvariantCulture, out _)); + Assert.ThrowsExactly(() => PreciseNumber.Parse(input, style, CultureInfo.InvariantCulture)); + } + + [TestMethod] + public void Parse_RejectsATrailingNarrowSpaceGroupSeparatorWhenTheStyleDoesNotAllowThousands() + { + // Shaped like fr-FR, whose group separator is U+202F: a stray one after the digits is not white space. + Assert.IsFalse(decimal.TryParse("1\u202F", NumberStyles.Integer, NarrowSpaceGroups, out _), "The BCL should reject this input too."); + Assert.IsFalse(PreciseNumber.TryParse("1\u202F", NumberStyles.Integer, NarrowSpaceGroups, out _)); + Assert.ThrowsExactly(() => PreciseNumber.Parse("1\u202F", NumberStyles.Integer, NarrowSpaceGroups)); + } + + [TestMethod] + [DataRow(" ")] + [DataRow("\t")] + [DataRow("\r")] + [DataRow("\n")] + [DataRow("\v")] + [DataRow("\f")] + public void Parse_TrimsAsciiWhiteSpaceAroundTheNumber(string white) + { + string input = white + "5" + white; + + Assert.IsTrue(PreciseNumber.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out PreciseNumber result)); + Assert.AreEqual(P("5"), result); + Assert.AreEqual(P("5"), PreciseNumber.Parse(input, NumberStyles.Integer, CultureInfo.InvariantCulture)); + } } diff --git a/PreciseNumber/PreciseNumber.cs b/PreciseNumber/PreciseNumber.cs index 060127d..927d098 100644 --- a/PreciseNumber/PreciseNumber.cs +++ b/PreciseNumber/PreciseNumber.cs @@ -1391,17 +1391,24 @@ private static PreciseNumber FromParsedParts(ReadOnlySpan digits, int deci return new((int)exponent, significand); } + /// + /// The white space that and + /// permit: U+0009 to U+000D and U+0020, as for the BCL numeric types. Other Unicode white space, such as a no-break + /// space or NEL, is not trimmed. + /// + private const string AllowedWhite = " \t\n\v\f\r"; + /// Trims the leading and trailing white space that allows. private static ReadOnlySpan TrimAllowedWhite(ReadOnlySpan s, NumberStyles style) { if (style.HasFlag(NumberStyles.AllowLeadingWhite)) { - s = s.TrimStart(); + s = s.TrimStart(AllowedWhite.AsSpan()); } if (style.HasFlag(NumberStyles.AllowTrailingWhite)) { - s = s.TrimEnd(); + s = s.TrimEnd(AllowedWhite.AsSpan()); } return s;