Skip to content

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

Description

@matt-edmondson

What's wrong

PreciseNumber.Parse(ReadOnlySpan<char>, NumberStyles, IFormatProvider?) (PreciseNumber/PreciseNumber.cs, around lines 1169-1310) applies only some of the NumberStyles flags. Whitespace trimming and AllowThousands follow the style. These parts do not:

  • The decimal separator is accepted whether or not AllowDecimalPoint is set.
  • The exponent (e/E) is accepted whether or not AllowExponent is set. Its digits then go through int.Parse(..., NumberStyles.Integer), which allows whitespace inside the exponent.
  • A leading - is always accepted (ReadLeadingSign, about line 1295). Only the positive sign is gated on AllowLeadingSign.

Reproduction (current main, net10.0, invariant culture)

Call PreciseNumber decimal.TryParse with the same style
Parse("1.5", NumberStyles.Integer, inv) 1.5 false
Parse("1e5", NumberStyles.Integer, inv) 100000 false
Parse("-5", NumberStyles.None, inv) -5 false
Parse("1e 5", NumberStyles.Float, inv) 100000 false
TryParse("1.5", NumberStyles.Integer, inv, out r) true, r = 1.5 false

Why it matters

PreciseNumber implements INumberBase<T>. Callers use T.TryParse(s, NumberStyles.Integer, ...) to check that input is a whole number, and NumberStyles.None to reject signs. With T = PreciseNumber those checks pass for fractional, exponent or negative text. The code then gets a value it had explicitly excluded, for example a count of -5 or 1.5, with no error. Every other BCL numeric type rejects these inputs.

Suggested fix / acceptance criteria

  • Accept the decimal separator only when style.HasFlag(NumberStyles.AllowDecimalPoint).
  • Accept e/E only when style.HasFlag(NumberStyles.AllowExponent). Parse the exponent digits with NumberStyles.AllowLeadingSign only, not Integer, so "1e 5" is rejected.
  • Accept a leading negative sign only when style.HasFlag(NumberStyles.AllowLeadingSign), matching the positive-sign check.
  • Add tests that compare against decimal.TryParse for the inputs in the table above. Include these cases, which must keep working: NumberStyles.Float / Any / the default Parse(string, provider) overload on "1.5", "-1.5e-3" and "1,234.5" (with Any).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreadyFully specified; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions