Skip to content

Honour AllowDecimalPoint, AllowExponent and AllowLeadingSign in Parse [patch] - #165

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/132-honour-number-styles
Oct 8, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/132-honour-number-styles

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #132

Problem

Parse(ReadOnlySpan<char>, NumberStyles, IFormatProvider?) accepted a decimal separator, an exponent and a leading minus sign whatever the style said. As a result, "1.5" and "1e5" parsed under NumberStyles.Integer, "-5" parsed under NumberStyles.None, and "1e 5" parsed under Float. Callers that validate input through INumberBase<T>.TryParse with a narrow style therefore received values they had excluded, which every BCL numeric type rejects.

Change (PreciseNumber.cs)

  • The decimal separator is read only when the style includes AllowDecimalPoint.
  • e/E is read only when the style includes AllowExponent. The exponent digits are now parsed with NumberStyles.AllowLeadingSign instead of Integer, so whitespace inside the exponent is rejected.
  • ReadLeadingSign now reads neither sign unless the style includes AllowLeadingSign. Before, it already applied this rule to the positive sign. That includes the ASCII hyphen kept for cultures that use U+2212.

Behavior change (for the changelog): callers passing NumberStyles.Integer or None now get a FormatException, or false from TryParse, for fractional, exponent or signed text. decimal behaves the same way. The default Parse(string, provider) and TryParse(string, provider, out) overloads use NumberStyles.Any, so they are unaffected.

Tests (PreciseNumberParseCultureTests)

  • TryParse_AcceptsWhatDecimalAccepts compares the result with decimal.TryParse for every input in the issue's table. It also covers inputs that must keep working: "1.5" with Float, "-1.5e-3" with Float and Any, "1,234.5" with Any, "-5" with Integer, and "1e+5" with Float.
  • Parse_ThrowsForWhatTheStyleDoesNotAllow checks the Parse (throwing) path for the same rejected inputs.
  • Parse_WithoutAStyleStillReadsFractionsExponentsAndSigns checks the default overload.
  • Parse_ReadsACulturesNegativeSignOnlyWhenTheStyleAllowsIt checks the U+2212 sign and the hyphen fallback under None and Float.

With the PreciseNumber.cs change reverted, 8 of these tests fail. With the change, the full suite passes locally: 469 of 469. dotnet format --verify-no-changes reports one IDE0001 finding at PreciseNumber.cs:2078. It is already on main and this PR doesn't touch that line.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FtvW1bPVVfCTF7fCWpeyRE


Generated by Claude Code

… [patch]

Parse(ReadOnlySpan<char>, NumberStyles, IFormatProvider?) accepted a
decimal separator, an exponent and a leading minus whatever the style
said, so "1.5" and "1e5" parsed under NumberStyles.Integer and "-5"
under NumberStyles.None. Code that validates input through
INumberBase<T>.TryParse with a narrow style let through values it had
excluded, where every BCL numeric type rejects them.

Each of the three is now read only when its flag is set, and the
exponent digits are parsed with AllowLeadingSign rather than Integer, so
"1e 5" is rejected too. Behaviour change: callers passing
NumberStyles.Integer or None now get a FormatException (or false from
TryParse) for fractional, exponent or signed text, as with decimal.

Fixes #132

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FtvW1bPVVfCTF7fCWpeyRE
@sonarqubecloud

sonarqubecloud Bot commented Oct 7, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit eaef3eb into main Oct 8, 2026
14 checks passed
@matt-edmondson
matt-edmondson deleted the fix/132-honour-number-styles branch October 8, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parse/TryParse ignore NumberStyles: "1.5" and "1e5" parse under NumberStyles.Integer, and "-5" parses under NumberStyles.None

2 participants