I would like to convert a string that is a negative number with thousand separator to integer.
I previously ran this code:
int ans = int.Parse(txtInt, System.Globalization.NumberStyles.AllowThousands);
But it produces a run-time error for negative number.
Any ideas on how to get the integer on a number string that has negative possibility?
I think you need to use NumberStyles.AllowLeadingSign also like;
int ans = int.Parse(txtInt, NumberStyles.AllowLeadingSign | NumberStyles.AllowThousands);
Without this member, your string can have only your current culture thousand separator except digits. With this member, you can also specify your string can have your current culture negative or positive sign as well in leading position.
Of course this will work only if you use NegativeSign of your CurrentCulture.
You can allow leading signs by setting the AllowLeadingSign flag like so:
int ans = int.Parse(txtInt, System.Globalization.NumberStyles.AllowThousands|System.Globalization.NumberStyles.AllowLeadingSign);
Related
I am migrating from an old MFC GUI to C#.
I was building a Form-based GUI when I've got an unexpected exception converting a string to an integer type. I assumed it would work the same as converting string to double.
string str = "1,000";
double dthou = Convert.ToDouble(str); // OK
int ithou = Convert.ToInt32(str); // raises an exception
Conversion to double gives correct value: 1000.0.
For int conversion, I was able to get a solution : Convert.ToInt32() a string with Commas.
But I am curious if there were any reason behind this.
Or, am I missing something?
I was able to find a similar, but not exactly a duplicate question :
Number parsing weirdness
[EDIT] after learning about the culture issue.
I am in a kind of a culture-shock because until now, in Korea, both floating point number and integer numbers are expressed with "," for thousands group and "." for decimal point (at least in the real world, in Korea, I mean, I think... ).
I guess I will have to accept current settings of MS Visual Studio and carry on.
[EDIT2] after sleeping over this issue.
I think it's more of the inconsistent handling of the formatted string. ToDouble accepts strings with thousands separator (in my culture, comma), but ToInt32 does not. If ToDouble is float | allowThousands, then why could'nt ToInt32 have been integer | allowThousands is what I am asking.
For the double conversion, there are two possibilities:
In your culture, , is the number group separator. And so the conversion succeeds and returns a value of 1000.
Alternatively, in your culture, , is used as the decimal separator. Again the conversion to floating point succeeds but this time returns 1.
For conversion to integer, "1,000" is simply not an integer. My suspicion, given your naming, is that , is a number group separator for you. And you are expecting it to be treated that way by ToInt32(). But ToInt32() does not accept number group separators. Valid characters for ToInt32() are 0 to 9, the optional sign prefix of - or + and leading or trailing whitespace.
In your profile, it says you are from South Korea. That's why I assume your current culture is ko-KR. (And you said as well.)
And it's NumberDecimalSeparator is . but it's NumberGroupSeparator is ,
Your Convert.ToDouble works and it assumes your , is a thousands seperator, not decimal seperator. That's why your dthou will be 1000 not 1.
Convert.ToInt32(string) uses Int32.Parse(string, CultureInfo.CurrentCulture) explicitly and this method implemented like;
public static int Parse(String s, IFormatProvider provider)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}
As you can see this method uses NumberStyles.Integer as a default. And that's why your string can be successfully parsed only it contasion one of these;
Leading white space
Trailing white space
Leading sign (positive or negative)
And since your string has thousands seperator or decimal seperator (this depends on which one you used for) this method throws exception.
Instead of that, you can use Int32.Parse(String, NumberStyles, IFormatProvider) overload which you can specify your NumberStyles like NumberStyles.AllowDecimalPoint or NumberStyles.AllowThousands
As an example;
string str = "1,000";
int ithou = Int32.Parse(str, NumberStyles.AllowThousands,
new CultureInfo("ko-KR"));
Console.WriteLine(ithou); // Prints 1000
If you want to get 1 as a result, you can use CultureInfo.Clone method to your culture and set it's NumberDecimalSeparator and NumberGroupSeparator properties like;
string str = "1,000";
CultureInfo c = (CultureInfo)CultureInfo.GetCultureInfo("ko-KR").Clone();
c.NumberFormat.NumberDecimalSeparator = ",";
c.NumberFormat.NumberGroupSeparator = ".";
int dthou = Int32.Parse(str, NumberStyles.AllowDecimalPoint, c);
Console.WriteLine(dthou ); // Prints 1
I don't think it's a cultural problem. It is the inconsistent handling
of the formatted string. ToDouble accepts strings with comma, but
ToInt32 does not. It's like going back to the original question again,
but couldn't ToInt32 be implemented to accept the comma just like
ToDouble function?
Oh my dear friend, you are still thinking wrong..
Everything is a culture problem in your case. There is no such a thing "Convert.ToDouble() accepts strings with comma, but Convert.ToInt32() does not".
Let's look at one more time how these methods are implemented.
Convert.ToDouble(string) uses Double.Parse(value, CultureInfo.CurrentCulture) explicitly and it is implemented like;
public static double Parse(String s, IFormatProvider provider)
{
return Parse(s, NumberStyles.Float| NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
}
With this NumberStyles.Float| NumberStyles.AllowThousands, you can use both decimal point or thousands separator in your code but , is your culture's NumberGroupSeparator not NumberDecimalSeparator. That's why your string will be parsed as a thousands seperetor. There is no such a thing Convert.ToDouble uses string with comma. It can be use your current culture's NumberDecimalSeparator or NumberGroupSeparator depends on which character your string has. If both were equal, NumberDecimalSeparator will be dominant and it will be used.
Convert.ToInt32(string) uses Int32.Parse(string, CultureInfo.CurrentCulture) explicitly and it's implemented like;
public static int Parse(String s, IFormatProvider provider)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}
As I said before, NumberStyles.Integer allows three things for your string; leading white space, trailing white space and leading positive or negative sign. It can't be parse if your string has decimal separator or thousands separator no matter it is comma or dot.
but couldn't ToInt32 be implemented to accept the comma just like
ToDouble function?
I told you before. Convert.ToInt32 doesn't have an overload takes NumberStyles as a parameter. You can use Int32.Parse(String, NumberStyles, IFormatProvider) overload which you can specify your NumberStyles enumeration for parsing your decimal separator or thousands separator.
In the english culture the decimal sign is "." . In the swedish culture the decimal sigh is ",". The myriad sign can be " ", "," or ".". So that's why C# throws an exception when the decimal sign is different than its culture specified.
Why is it when I'm parsing a decimal (0) ToString my string shows as empty when using the method:
String somthing = someDecimal.ToString("#")
And when I'm using:
String somthing = somDecimal.ToString("0.##")
The string shows up as 0?
When I'm looking at the value in the debug mode in both way it's says they have a "0" in them.
From The "#" Custom Specifier
Note that this specifier never displays a zero that is not a
significant digit, even if zero is the only digit in the string. It
will display zero only if it is a significant digit in the number that
is being displayed.
If you want to display digits after your decimal point, you need to use 0.00 instead of 0.##.
Because pound "#" means convert to symbol if there is a number. 0 is an "empty" number, so it converts to "".
In fact, in second case, you get 0, as you imply to show at least one digit before dot.
This all is by design convention of C# language.
MSDN: the "#" Custom Specifier
The "#" custom format specifier serves as a digit-placeholder symbol.
If the value that is being formatted has a digit in the position where
the "#" symbol appears in the format string, that digit is copied to
the result string. Otherwise, nothing is stored in that position in
the result string. Note that this specifier never displays a zero that
is not a significant digit, even if zero is the only digit in the
string. It will display zero only if it is a significant digit in the
number that is being displayed.
So if the decimal would be 1 instead of 0 it would be diplayed even with ToString("#").
If you want a fixed number of decimals after the decimal point, you need to use
String somthing = somDecimal.ToString("0.00")
In your example you use the # specifier which means 'put here a number if there is a meaningful number'.
It would work if someDecimal is 0.01
decimal somDecimal = 0.01m
String somthing = somDecimal.ToString("0.##");
but not if
decimal somDecimal = 0.01m
String somthing = somDecimal.ToString("0.#");
So always add a comma and have it to two decimal places, "F" nearly works but can't find the right solution
decimal = 1000.5
test.Text = decimal.ToString("F")
I've also tried:
String.Format("{0:#,###.##}", decimal);
I want to display as the string as 1,000.50
Try:
String.Format("{0:#,###.00}", decimalNumber);
See: Custom Numeric Format Strings
0 - Zero placeholder Replaces the zero with the corresponding digit if
one is present; otherwise, zero appears in the result string. More
information: The "0" Custom Specifier.
It is not going to round the numbers, it is just string formatting.
For culture insensitive formatting do:
String.Format(CultureInfo.InvariantCulture, "{0:#,###.00}", decimalNmber);
String.Format(CultureInfo.InvariantCulture, "{0:0,0.00}", decimal)
For more options see this link.
And here you can test this online.
Guys, I have a string that contains a decimal number. The problem is, sometimes it is negative and it is stored in accounting format (positive number surrounded by parenthesis). In other words, I got a string like this:
string s = "(35.00)";
What I'm doing currently is:
decimal TheValue = decimal.Parse(s);
This value of TheValue should be -35.00. It apparently doesn't know what the parenthesis mean, so its just storing 0 in Thevalue. Anyone know how to make the decimal.Parse() function look for parenthesis?
Take a look at the decimal.Parse overload that accepts a NumberStyles enum. Specifically, you'll need to include NumberStyles.AllowParentheses.
Is there any way I can specify a standard or custom numeric format string to always output the sign, be it +ve or -ve (although what it should do for zero, I'm not sure!)
Yes, you can.
There is conditional formatting. See Conditional formatting in MSDN
eg:
string MyString = number.ToString("+0;-#");
Where each section separated by a semicolon represents positive and negative numbers
or:
string MyString = number.ToString("+#;-#;0");
if you don't want the zero to have a plus sign.
Beware, when using conditional formatting the negative value doesn't automatically get a sign. You need to do
string MyString = number.ToString("+#;-#;0");
You can also use format strings in string.Format(); the format string is separated from the index with a colon (':')
var f = string.Format("{0}, Force sign {0:+#;-#;+0}, No sign for zero {0:+#;-#;0}", number);
For number { +1, -1, 0 } this gives:
1, Force sign +1, No sign for zero +1
-1, Force sign -1, No sign for zero -1
0, Force sign +0, No sign for zero 0
You can also use an interpolated string instead of string.Format to obtain the same result:
var f = $"{number}, Force sign {number:+#;-#;+0}, No sign for zero {number:+#;-#;0}";
Contrary to the other answers it seems that if you want to get +1, -1, +0 (for arguments 1, -1, 0) you need to use the format:
String.Format("{0:+#;-#;+0}", 0)); // output: +0
or
String.Format("{0:+0;-#}", 0)); // output: +0
If you use just +#;-# it will display just + (not +0) for 0.
The "#" Custom Specifier (at https://msdn.microsoft.com/en-us/library/0c899ak8.aspx)
Note that this specifier never displays a zero that is not a significant digit, even if zero is the only digit in the string. It will display zero only if it is a significant digit in the number that is being displayed.
Also please keep in mind that if you need any decimal precision you need to specify it like that:
String.Format("{0:+0.##;-#.##}", 0)); // output: +0
or, if you wan't zeros to always show up, like that:
String.Format("{0:+0.00;-#.00}", 0)); // output: +0.00
For a numeric expression of any type:
+###,###,###,###,###,###,###,###,###,##0.###,###,###,###,###,###,###,###,###,###;-###,###,###,###,###,###,###,###,###,##0.###,###,###,###,###,###,###,###,###,###;0
Use three parts for three cases: positive;negative;zero
Other aspects of the example:
Zero is not signed. You could have it show as anything, such as "zero".
Absolute values less than one have a leading 0 before the decimal point. Adjust to taste.
Number of digits is for the largest and smallest absolute decimal values. Adjust to taste.
Decimal point character is culture-specific. .NET substitutes.
Grouping separators are optional. The character is culture-specific. .NET substitutes. (The positions are also culture-specific but that's only controlled by your format string.) You also use any other character except the special characters for Format (which include , . # 0).
I cannot comment so i Do an answer here (nuts reputation system ....)
You can Use number.ToString("+0;-#") very well to Produce the UTC String TimeFormat
Here showed in PowerShell code
"$([System.DateTime]::Now.ToString('HH:mm:ss.fff'))$($([System.TimeZoneInfo]::Local.GetUtcOffset([System.DateTime]::Now).TotalMinutes.ToString('+0;-#')))"
Thank you #gcores https://stackoverflow.com/users/40256/gcores