25

In C#:

This throws a FormatException, which seems like it shouldn't:

Int32.Parse("1,234");

This does not, which seems normal:

Single.Parse("1,234");

And surprisingly, this parses just fine:

Single.Parse("1,2,3,4"); //Returns 1234

My local culture is EN-US, so , is the default thousands separator char.

Main question: Why the inconsistency?

Also: Why does Parse("1,2,3,4") work? It appears to just be removing all instances of the local separator char before parsing. I know there would be extra runtime overhead in a regex check or something like that, but when would the numeric literal "1,2,3,4" not be a typo?


Related: C# Decimal.Parse issue with commas

7
  • Interesting.. Single.Parse("1,2,3,4", NumberFormatInfo.InvariantInfo); also outputs 1234.
    – Sinatr
    Commented Mar 2, 2016 at 15:25
  • 9
    There is no inconsistency here. Int32.Parse() defaults to NumberStyles.Integer for its second argument, which does not support the thousands separator. On the other hand, Single.Parse() defaults to NumberStyles.Float | NumberStyles.AllowThousands, which, well, allows thousands separators. See the Remarks section in the documentation for the latter. Commented Mar 2, 2016 at 15:26
  • 4
    @FrédéricHamidi I would still argue that there is inconsistency between the parsing defaults for Int32 and Single. The fact that the inconsistency is explainable does not make them consistent.
    – D Stanley
    Commented Mar 2, 2016 at 15:33
  • 2
    @FrédéricHamidi That seems to be the very definition of inconsistency. Commented Mar 2, 2016 at 15:34
  • 2
    For the third example, the parser just removes thousands separators from the string - this is a known "feature" of the parser.
    – D Stanley
    Commented Mar 2, 2016 at 15:38

3 Answers 3

12

According to MSDN:

The s parameter contains a number of the form:

[ws][sign]digits[ws]


The s parameter is interpreted using the NumberStyles.Integer style. In addition to decimal digits, only leading and trailing spaces together with a leading sign are allowed.

That's it, NumberStyles.Integer disallows the Parse method to use the thousands separator, whereas Single.Parse uses by default NumberStyles.Float and NumberStyles.AllowThousands. You can change this behaviour by specifiying the second argument as NumberStyles:

Int32.Parse("1,234", NumberStyles.AllowThousands); //works

Single.Parse ignores the grouping and doesn't use culture-specific NumberGroupSizes at all, and only determines if the character is a group or decimal separator. The group sizes are used only when formatting numbers.

11

For the first case, from Microsoft Source Code Reference, by default Int32.Parse implements NumberStyles.Integer but not NumberStyles.AllowThousands

public static int Parse(String s) {
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}

Thus any comma separator is not allowed. This:

Int32.Parse("1,234");

or

Int32.Parse("1.234"); 

will both be wrong. In any culture.

To fix it, NumberStyles.AllowThousands must be added to the NumberStyles which will allow "1,234" to be parsed in EN-US culture:

Int32.Parse("1,234", NumberStyles.Integer | NumberStyles.AllowThousands);

But

Int32.Parse("1.234", NumberStyles.Integer | NumberStyles.AllowThousands);

Will still throw an Exception.


For the second case, according to Microsoft Code Source Reference, the default style for Single.Parse is:

public static float Parse(String s) {
    return Parse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
}

Which allows thousands separator. And "," is recognized as thousand separator in EN-US culture, for Single.Parse and thus you get the second case parsed correctly

Single.Parse("1,234"); //OK

And obviously "1.234" will also be correct, except that "." is not recognized as thousand separators but decimal separator.


As for the third case, Internally, Single.Parse calls TryStringToNumber, and Parse.Number which would simply ignore the thousand separators. Thus you get:

Single.Parse("1,2,3,4"); //Returns 1234 

Because it is equivalent as

Single.Parse("1234"); //Returns 1234 
1
  • 1
    Doesn't the OP say Int32.Parse("1,234"); throws a FormatException though?
    – weston
    Commented Mar 2, 2016 at 15:38
2

mine is es-ES On these . is the default thousands separator char, and "," the separate character between int and double So any parse like "1.2.3,4" gives me "123,40" ( 123.40 on US ) If i put the "." before the "," like "123,4.3" it gives error but, the same way the questions says, if i put "1.2.3.4" gives me "1234" So, may be it is a functionality of the .net itself.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.