I'm getting an exception when trying to parse a number that is in scientific notation. Looking at other posts on how to do it, and I can't tell what I'm doing any differently than those.
I've tried the following:
System.Convert.ToInt64("1.0206e+06");
System.Convert.ToInt64("1.0206E+06"); // Uppercase 'E'
These result in a FormatException: Input string was not in the correct format.
I tried these:
Int64.Parse("1.0206e+06", System.Globalization.NumberStyles.Any);
Int64.Parse("1.0206e+06", System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
Int64.Parse("1.0206e+06", System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture);
These all result in an OverflowException: Value was too large or too small.
Also tried with Int32.Parse and got the same exception and message:
(long)Int32.Parse(str, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
Using Decimal.Parse works with the same string and parameters passed to it:
(long)Decimal.Parse(str, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
This answer suggests using this:
Double.Parse("1.234567E-06", System.Globalization.NumberStyles.Float);
Which is similar to my last example, I just accept all number styles, and that answer used a negative exponent. In fact, I fed that exact string into my examples and I still get the same exceptions.
Not sure if it matters, but I'm using Mono C#, the version that comes with Unity.
Here's the C# source file: https://github.com/Unity-Technologies/mono/blob/unity-staging/mcs/class/corlib/System/Int64.cs. The exception is thrown on line 469 and doesn't provide me a call stack before that point. But I'm guessing the exception is created on line 355 or 372 since those match the exception type and message I'm being shown.
I'm going to assume that this is a bug with the version of Mono C# I'm using, which comes with Unity 5.5.x or earlier. Their repository can be found here.
Their implementation of Int64.Parse does not even check for the NumberStyles.AllowExponents flag, or handle exponents in any way. So it's going to fail when it finds the + symbol in the string. Basically, Int64.Parse when using Unity does not support exponents.
Mono's Int32.Parse does seem to look for exponents, but still causes an OverflowException with all exponents that I give it.
Decimal.Parse actually does work with the same parameters as the other two, which suggests there was nothing wrong with the string or parameters, but it's just a bug in their other Parse methods. Decimal's parsing is completely different from how the Int parsing is being done, so that may explain why it works and the others don't.
Related
When I learned about the String.Format function, I did the mistake to think that it's acceptable to name the placeholders after the colon, so I wrote code like this:
String.Format("A message: '{0:message}'", "My message");
//output: "A message: 'My message'"
I just realized that the string behind the colon is used to define the format of the placeholder and may not be used to add a comment as I did.
But apparently, the string behind the colon is used for the placeholder if:
I want to fill the placeholder with an integer and
I use an unrecognized formating-string behind the colon
But this doesn't explain to me, why the string behind the colon is used for the placeholder if I provide an integer.
Some examples:
//Works for strings
String.Format("My number is {0:number}!", "10")
//output: "My number is 10!"
//Works without formating-string
String.Format("My number is {0}!", 10)
//output: "My number is 10!"
//Works with recognized formating string
String.Format("My number is {0:d}!", 10)
//output: "My number is 10!"
//Does not work with unrecognized formating string
String.Format("My number is {0:number}!", 10)
//output: "My number is number!"
Why is there a difference between the handling of strings and integers? And why is the fallback to output the formating string instead of the given value?
Just review the MSDN page about composite formatting for clarity.
A basic synopsis, the format item syntax is:
{ index[,alignment][:formatString]}
So what appears after the : colon is the formatString. Look at the "Format String Component" section of the MSDN page for what kind of format strings are predefined. You will not see System.String mentioned in that list. Which is no great surprise, a string is already "formatted" and will only ever appear in the output as-is.
Composite formatting is pretty lenient to mistakes, it won't throw an exception when you specify an illegal format string. That the one you used isn't legal is already pretty evident from the output you get. And most of all, the scheme is extensible. You can actually make a :message format string legal, a class can implement the ICustomFormatter interface to implement its own custom formatting. Which of course isn't going to happen on System.String, you cannot modify that class.
So this works as expected. If you don't get the output you expected then this is pretty easy to debug, you've just go two mistakes to consider. The debugger eliminates one (wrong argument), your eyes eliminates the other.
String.Format article on MSDN has following description:
A format item has this syntax: { index[,alignment][ :formatString] }
...
formatString Optional.
A string that specifies the format of the
corresponding argument's result string. If you omit formatString, the
corresponding argument's parameterless ToString method is called to
produce its string representation. If you specify formatString, the
argument referenced by the format item must implement the IFormattable
interface.
If we directly format the value using the IFormattable we will have the same result:
String garbageFormatted = (10 as IFormattable).ToString("garbage in place of int",
CultureInfo.CurrentCulture.NumberFormat);
Console.WriteLine(garbageFormatted); // Writes the "garbage in place of int"
So it seems that it is something close to the "garbage in, garbage out" problem in the implementation of the IFormattable interface on Int32 type(and possibly on other types as well). The String class does not implement IFormattable, so any format specifier is left unused and .ToString(IFormatProvider) is called instead.
Also:
Ildasm shows that Int32.ToString(String, INumberFormat) internally calls
string System.Number::FormatInt32(int32,
string,
class System.Globalization.NumberFormatInfo)
But it is the internalcall method (extern implemented somewhere in native code), so Ildasm is of no use if we want to determine the source of the problem.
EDIT - CULPRIT:
After reading the How to see code of method which marked as MethodImplOptions.InternalCall? I've used the source code from Shared Source Common Language Infrastructure 2.0 Release (it is .NET 2.0 but nonetheless) in attempt to find a culprit.
Code for the Number.FormatInt32 is located in the ...\sscli20\clr\src\vm\comnumber.cpp file.
The culprit could be deduced from the default section of the format switch statement of the FCIMPL3(Object*, COMNumber::FormatInt32, INT32 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE):
default:
NUMBER number;
Int32ToNumber(value, &number);
if (fmt != 0) {
gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
break;
}
gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
break;
The fmt var is 0, so the NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt); is being called.
It leads us to nothing else than to the second switch statement default section in the NumberToStringFormat method, that is located in the loop that enumerates every format string character. It is very simple:
default:
*dst++ = ch;
It just plain copies every character from the format string into the output array, that's how the format string ends repeated in the output.
From one point of view it allows to really use garbage format strings that will output nothing useful, but from other point of view it will allow you to use something like:
String garbageFormatted = (1234 as IFormattable).ToString("0 thousands and ### in thousand",
CultureInfo.CurrentCulture.NumberFormat);
Console.WriteLine(garbageFormatted);
// Writes the "1 thousands and 234 in thousand"
that can be handy in some situations.
Interesting behavior indeed BUT NOT unaccounted for.
Your last example works when
if String.Format("My number is {0:n}!", 10)
but revert to the observed beahvior when
if String.Format("My number is {0:nu}!", 10)`.
This prompts to search about the Standard Numeric Format Specifier article on MSDN where you can read
Standard numeric format strings are used to format common numeric
types. A standard numeric format string takes the form Axx, where:
A is a single alphabetic character called the format specifier. Any
numeric format string that contains more than one alphabetic
character, including white space, is interpreted as a custom numeric
format string. For more information, see Custom Numeric Format
Strings.
The same article explains: if you have a SINGLE letter that is not recognized you get an exception.
Indeed
if String.Format("My number is {0:K}!", 10)`.
throws the FormatException as explained.
Now looking in the Custom Numeric Format Strings chapter you will find a table of eligible letters and their possible mixings, but at the end of the table you could read
Other
All other characters
The character is copied to the result string unchanged.
So I think that you have created a format string that cannot in any way print that number because there is no valid format specifier where the number 10 should be 'formatted'.
No it's not acceptable to place anything you like after the colon. Putting anything other than a recognized format specifier is likely to result in either an exception or unpredictable behaviour as you've demonstrated. I don't think you can expect string.Format to behave consistently when you're passing it arguments which are completely inconsistent with the documented formatting types
I do not understand why I have to specify NumberStyles.Float when using decimal.Parse and not for double.Parse
I can do:
var tmp = double.Parse("1e-2");
but not:
var tmp1 = decimal.Parse("1e-2");
Because a System.FormatException (Input string was not in a correct format) is thrown
var tmp1 = decimal.Parse("1e-2", System.Globalization.NumberStyles.Float);
someone can tell me if there is a good reason behind this behavior
It's just behaving as documented. From Double.Parse:
The s parameter is interpreted using a combination of the NumberStyles.Float and NumberStyles.AllowThousands flags.
Note that NumberStyles.Float includes NumberStyles.AllowExponent.
From Decimal.Parse:
Parameter s is interpreted using the NumberStyles.Number style.
NumberStyles.Number does not include NumberStyles.AllowExponent.
I can't reproduce your bizarre stack traces which appear to show the same call failing just after it's worked:
Decimal.Parse("1e-2") always fails for me
Decimal.Parse("1e-2", NumberStyles.Float) always works for me
Double.Parse("1e-2") always works for me
Double.Parse("1e-2", NumberStyles.Float) always works for me
As for why the "default" number style differs between the two - I suspect it's because double values typically are used in scientific scenarios where exponent-based representations are common, but decimal values typically aren't.
I am trying to parse some string to a double value, using this parse method overload:
double.Parse("198.222213745118", CultureInfo.CurrentUICulture);
the CultureInfo.CurrentUICulture is fr-FR.
but this is throwing an exception of type FormatException.
What can be the reason?
French (i.e. fr-FR) use a comma to denote the start of the decimal part, not a period. They use a period to separate thousands.
I know this question is old but my answer might help someone else.
So this is the answer:
double.Parse("198.222213745118", System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.NumberFormatInfo.InvariantInfo);
instead of
double.Parse("198.222213745118", CultureInfo.CurrentUICulture);
I suggest using the Double.TryParse rather than the .Parse as it is safer to use and makes sure you dont get any exception on parsing.
Here is a Code for you to use,
double answer = -1;
Double.TryParse("Value", out answer);
Now all you have to do is do a conditional statement that'll check if it indeed parsed' the string.
I'm receiving an error which looks like it is due to an error using hexidecimal inputs in a uint field. It occurs on both versions of the web service I'm working on.
System.ArgumentException: Cannot convert 0x2 to System.UInt32.
Parameter name: type ---> System.FormatException: Input string was not in a correct format.
However, my coworker says that it works for him on a previous version of the web service I have, when he calls it using C++, but it doesn't work on the current version I'm working on.
Has anyone experienced this?
Are you using something like this in your code? If not, try to implement this (replace "CF01" with your input value):
int i = Convert.ToInt32("CF01", 16);
Edit:
For the particular case with the 0x prefix:
public int32 GetInt32FromHex(string h) {
h = h.substring(2, (h.length - 2));
return convert.ToInt32(h, 16);
}
This is quite an interesting error because it seems like the Parse method of UInt32 is only able to parse numbers of the form [ws][sign]digits[ws] per the documentation. There is a version of the method that can take NumberStyles flags see documentation. One of the values of this is AllowHexSpecifier which you'd think would allow the 0x. However if you read the documentation for both the Parse method and the NumberStyles unable to handle the 0x format at all. If you look at the it says:
If s is the string representation of a hexadecimal number, it cannot be preceded by any decoration (such as 0x or &h) that differentiates it as a hexadecimal number. This causes the conversion to fail.
The AllowHexSpecifier makes it so that only numbers of the form [ws]hexdigits[ws]
It seems like you are going to have to get rid of the leading 0x before parsing or use another method of parsing.
One way to do that, especially if there is a leading 0x is to do the following:
var value = UInt32.Parse( "0x2".TrimStart('0').TrimStart('x'));
You will have to be careful here to do checking to make sure you have the proper base though and you may need to use the NumberStyles.AllowHexSpecifier to parse correctly.
I tried searching google and stackoverflow without success.
I'm having a problem with "Input string was not in a correct format." exception with an application I'm working at.
Thing is, that I convert some double values to strings with doubleNumber.ToString("N2"); in order to store them in XML file. When I switch testing machines, XML file stored on one can't be returned back to double values.
I've tried all of the solutions I could think of, but setting number culture didn't work, using CultureInfo.InvariantCulture, replacing characters also doesn't work. Sometimes the values are stored like "3,001,435.57" and sometimes (on other PC) like "3.001.435,57".
Is there some function or a way to parse a double from string, whatever the input format is?
Thanks.
You have to specify a culture because (eg.) "3,001" is ambiguous - is it 3.001 or 3001?
Depending on what your numbers look like, perhaps you could attempt to detect the culture by counting number of , and . characters and/or checking their positions.
Here is what you are looking for...
http://msdn.microsoft.com/en-us/library/9s9ak971.aspx
This will accept a string variable and a format provider. You need to create a format provider that provides the culture information you are looking to convert out of.