I have no idea why this is not working:
string s = "12,00 €";
var germanCulture = CultureInfo.CreateSpecificCulture("de-DE");
decimal d;
if (decimal.TryParse(s, NumberStyles.AllowCurrencySymbol, germanCulture, out d))
{
// i want to get to this point
Console.WriteLine("Decimal value: {0}", d);
}
Use NumberStyles.Currency instead of NumberStyles.AllowCurrencySymbol
if (decimal.TryParse(s, NumberStyles.Currency, germanCulture, out d))
and the output for you code would be:
Decimal value: 12.00
Try this;
string.Format(new CultureInfo("en-SG", false), "{0:c0}", 123423.083234);
It will convert 123423.083234 to $1,23,423 format.
Please note that this doesn't work with the bitcoin symbol and other cryptocurrency symbols yet, unfortunately. I tried both ways.
Sharplab proof: link
A workaround in my case (I have a minus sign followed by the bitcoin ฿ symbol) would be to do
a .Where() on string ignoring everything except numbers and minus sign... But if you want general validation... Well then you'll have to hardcode these bitcoin etc symbols somewhere
Related
post.Min.ToString("0.00").Replace(",", ".").Replace(".00", string.Empty)
post.Min is a double such as 12,34 or 12,00. Expected output is 12.34 or 12.
I basically want to replace the comma by a point, and cut the .00 part if any.
I am asking because I couldn't find anything, or because I don't exactly know what to search. This has an high change of being a duplicate, I simply can't find it. Please let me know.
The simplest solution would appear to be to use CultureInfo.InvariantCulture, and I reject the suggestion that this is any more complicated than using a series of replaces as you demonstrated in your question.
post.Min.ToString("0.##", CultureInfo.InvariantCulture);
# is the digit placeholder, described as the docs like this:
Replaces the "#" symbol with the corresponding digit if one is present; otherwise, no digit appears in the result string.
Try it online
If you use this in a lot of places, and that's why you want to keep it simple, you could make an extension method:
public static class MyExtensions
{
public static string ToHappyString(this double value)
{
return value.ToString("0.##", CultureInfo.InvariantCulture);
}
}
And then you just have to call .ToHappyString() wherever you use it. For example, post.Min.ToHappyString()
You can use .ToString("0.##").
like,
// Considered german culture; May be this is your current culture
CultureInfo culture = new CultureInfo("de");
double number1 = Double.Parse("12,34", culture);
double number2 = Double.Parse("12,00", culture);
Console.WriteLine(number1.ToString("0.##"));
Console.WriteLine(number2.ToString("0.##"));
Output:
12.34
12
.Net fiddle
Checkout the ToString overloads article on MSDN about examples of the N format. This is also covered in the Standard Numeric Format Strings article.
Relevant examples:
// Formatting of 1054.32179:
// N: 1,054.32
// N0: 1,054
// N1: 1,054.3
// N2: 1,054.32
// N3: 1,054.322
For the dot instead of comma to do it properly, in combination with N0 use:
System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
customCulture.NumberFormat.NumberDecimalSeparator = ".";
System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
double.ToString("0.##") to consider decimal places only if not .00 and you can create your own Number Format without using Culture:
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalSeparator = ".";
post.Min.ToString("0.##", nfi);
I want to parse a string from an Text input to decimal. The value represents a currency value.
Currently i got this solution:
private Decimal CastToDecimal(string value)
{
Decimal result;
var valid = Decimal.TryParse(value, NumberStyles.Currency, null, out result);
return valid ? result : -1;
}
This works pretty well so far, except for possible culture-differences. I'm german and i expect most users to enter german-style puctuation. But it is possible that someone uses "." instead of "," and the conversion will fail.
"123,45€" => 123.45
"123.456,78€" => 123456.78
"123.45€" => 12345 <- I want the result to be 123.45 here
Is there a way to automatically detect the used culture for a decimal value? Such that it does not matter if you use german or english punctuation, you still get the same result?
Update:
Thanks to your help, i created a method which does what i want (i think).
private static Decimal CastToDecimal(string value)
{
Decimal resultDe;
Decimal resultEn;
var style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
var cultureDe = CultureInfo.CreateSpecificCulture("de-DE");
var cultureEn = CultureInfo.CreateSpecificCulture("en-GB");
var deValid = Decimal.TryParse(value, style, cultureDe, out resultDe);
var enValid = Decimal.TryParse(value, style, cultureEn, out resultEn);
var minVal = Math.Min(resultDe, resultEn);
var maxVal = Math.Max(resultDe, resultEn);
if (!deValid)
return resultEn;
if (!enValid)
return resultDe;
return BitConverter.GetBytes(decimal.GetBits(minVal)[3])[2] > 2 ? maxVal : minVal;
}
This code...
Console.WriteLine(CastToDecimal("123,45"));
Console.WriteLine(CastToDecimal("123.45"));
Console.WriteLine(CastToDecimal("123,450"));
Console.WriteLine(CastToDecimal("123.450"));
Console.WriteLine(CastToDecimal("123.123,45"));
Console.WriteLine(CastToDecimal("123,123.45"));
returns this:
123,45
123,45
123450
123450
123123,45
123123,45
the solution at http://msdn.microsoft.com/en-us/library/3s27fasw%28v=vs.110%29.aspx
which includes setting the NumberStyle may be helpful.
...
value = "1.345,978";
style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands;
culture = CultureInfo.CreateSpecificCulture("es-ES");
if (Double.TryParse(value, style, culture, out number))
Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
Console.WriteLine("Unable to convert '{0}'.", value);
// Displays:
// Converted '1.345,978' to 1345.978.
value = "1 345,978";
if (Double.TryParse(value, style, culture, out number))
Console.WriteLine("Converted '{0}' to {1}.", value, number);
else
Console.WriteLine("Unable to convert '{0}'.", value);
...
I encountered the same problem some time ago. My solution was writing my own parser in Java. The algorithm first cleans up the string. Brief description follows:
Scan string from left to right
If char = '.' then dotFound=true ; lastSeparatorPosition = index ; dots++
If char = ',' then commaFound=true ; lastSeparatorPosition = index ; commas++
If dots == 0 && commas == 0 then its an integer => done
If dots > 0 && commas > 0 then the one at lastSeparatorPosition is the decimal separator. Remove the others from the string => done
/* only one separator type */ if ( dots + commas ) > 1 then remove them // because must be thousands separator => done
/* separator occurs once */ if numberOfDigits right of separator == 3 then you have to decide :-) either integer or decimal with 3 digits in fraction
7 is the only remaining problem like chiastic-security already stated. Here you can only decide taken the conceptual environment into account. All other cases are safe.
Have fun
This can't be done, simply because there are strings that are meaningful in two different cultures, but mean different things. For instance:
123.456
123,456
The first is a bit over 123 in the UK, but 123456 in Germany; the second is 123456 in the UK but a bit over 123 in France.
The only solution is to add validation on input and give user and example by the way if it is a webpage then find a way to get input according to user's culture. I suggests you to not to try to do what you are trying because there are some culture which contradict each others for example in currency;
US/Australia/Many others uses following format
45,999.95
where , is thousand separator and . is decimal separator
whereas in some European countries
45.999,95
means the same as above but thousands separator is . and , is used as decimal separator.
Now issue is there is no guarantee that user use both separator and your system may assume thousand separator as decimal and so on.
If you really don't want to bother user then make separate input fields for major and minor currencies.
So its better to not to go there. I believe this may help. Happy Coding :)
Update:
Same case is with date format e.g. in US format month comes first and then day whereas in Australia day comes first and then month now 02/01/2015 input will mean differently system can't tell the intention of user.
This is probably dumb but it's giving me a hard time. I need to convert/format a double to string with a mandatory decimal point.
1 => 1.0
0.2423423 => 0.2423423
0.1 => 0.1
1234 => 1234.0
Basically, I want to output all decimals but also make sure the rounded values have the redundant .0 too. I am sure there is a simple way to achieve this.
Use double.ToString("N1"):
double d1 = 1d;
double d2 = 0.2423423d;
double d3 = 0.1d;
double d4 = 1234d;
Console.WriteLine(d1.ToString("N1"));
Console.WriteLine(d2.ToString("N1"));
Console.WriteLine(d3.ToString("N1"));
Console.WriteLine(d4.ToString("N1"));
Demo
Standard Numeric Format Strings
The Numeric ("N") Format Specifier
Update
(1.234).ToString("N1") produces 1.2 and in addition to removing additional decimal digits, it also adds a thousands separator
Well, perhaps you need to implement a custom NumberFormatInfo object which you can derive from the current CultureInfo and use in double.ToString:
var culture = CultureInfo.CurrentCulture;
var customNfi = (NumberFormatInfo)culture.NumberFormat.Clone();
customNfi.NumberDecimalDigits = 1;
customNfi.NumberGroupSeparator = "";
Console.WriteLine(d1.ToString(customNfi));
Note that you need to clone it since it's readonly by default.
Demo
There is not a built in method to append a mandatory .0 to the end of whole numbers with the .ToString() method, as the existing formats will truncate or round based on the number of decimal places you specify.
My suggestion is to just roll your own implementation with an extension method
public static String ToDecmialString(this double source)
{
if ((source % 1) == 0)
return source.ToString("f1");
else
return source.ToString();
}
And the usage:
double d1 = 1;
double d2 = 0.2423423;
double d3 = 0.1;
double d4 = 1234;
Console.WriteLine(d1.ToDecimalString());
Console.WriteLine(d2.ToDecimalString());
Console.WriteLine(d3.ToDecimalString());
Console.WriteLine(d4.ToDecimalString());
Results in this output:
1.0
0.2423423
0.1
1234.0
You could do something like this: if the number doesn't have decimal points you can format its output to enforce one decimal 0 and if it has decimal places, just use ToString();
double a1 = 1;
double a2 = 0.2423423;
string result = string.Empty;
if(a1 - Math.Floor(a1) >0.0)
result = a1.ToString();
else
result = a1.ToString("F1");
if (a2 - Math.Floor(a2) > 0.0)
result = a2.ToString();
else
result = a2.ToString("F1");
When you use "F" as formatting, the output won't contain thousands separator and the number that follows it specifies the number of decimal places.
Use ToString("0.0###########################").
It does work. I found it in duplicate of your question decimal ToString formatting which gives at least 1 digit, no upper limit
Double provides a method ToString() where you can pass an IFormatProvider-object stating how you want your double to be converted.
Additionally, it should display trailing 0 at all costs.
value = 16034.125E21;
// Display value using the invariant culture.
Console.WriteLine(value.ToString(CultureInfo.InvariantCulture));
// Display value using the en-GB culture.
Console.WriteLine(value.ToString(CultureInfo.CreateSpecificCulture("en-GB")));
// Display value using the de-DE culture.
Console.WriteLine(value.ToString(CultureInfo.CreateSpecificCulture("de-DE")));
// This example displays the following output to the console:
// -16325.62015
// -16325.62015
// -16325,62015
// 1.6034125E+25
// 1.6034125E+25
// 1,6034125E+25
Here is the documentation from MSDN.
You can cast to string and then appen ".0" if there was no decimal point given
string sValue=doubleValue.ToString();
if(!sValue.Contains('.'))
sValue+=".0";
EDIT:
As mentioned in the comments '.' may not be the decimal seperator in the current culture. Refer to this article to retrieve the actual seperator if you want make your code save for this case.
i have the following code:
static void Main(string[] args)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("mk-MK");
string s2 = "4.434,00";
double d;
if (Double.TryParse(s2, NumberStyles.Number, CultureInfo.CurrentCulture, out d))
{
//String.Format("{0:0.0,00}", d);
Console.WriteLine(d + " Type of: " + d.GetType());
}
else
{
Console.WriteLine("ne go parsirashe");
}
String.Format("{0:0.0,00}", d);
Console.WriteLine(d);
//Console.WriteLine(String.Format("{0:0,0.00}", d));
//Console.WriteLine(s2.GetType().ToString());
//Console.ReadLine();
//String.Format("{0:0.0,00}"
Console.ReadLine();
The output is: 4434 Type of: System.Double
4434
Why isn't the value of d in the format of : 4.434,00 ? Can you please help me with this? I've sent couple of hours trying to figure this out before trying to reach out to you guys. Thanks!!!
You are discarding your formatted string - you are not assigning it to a string and simply outputting the double to the console (which would call ToString() on it).
Try this:
string forDisplay = string.Format("{0:0.0,00}", d);
Console.WriteLine(forDisplay);
Or, even shorter:
Console.WriteLine(string.Format("{0:0.0,00}", d));
Update:
In order to format the string according to your culture, you will need to use the Format overload that takes an IFormatProvider (i.e. a culture) and ensure that the format string uses the right characters for the different parts (, for standard thousands separator and . for standard decimal separator - see here for the meanings of each such character in a format string):
var res = String.Format(CultureInfo.CurrentCulture, "{0:0,0.00}", d);
Console.WriteLine(forDisplay);
Result:
4.434,00
You meant to do:
string formatted = String.Format("{0:0.0,00}", d);
Console.WriteLine(formatted);
string.Format returns a string -- it cannot affect the formatting of a double, since doubles have no formatting at all. Doubles only store the raw numeric value (as bits, internally).
You have the . and , around the wrong way, if I'm understanding what you're trying to do.
If you read the Custom Numeric Format Strings page on MSDN, you can see that you need to use , for the thousands separator, and . for the decimal separator, and (the important part) the target culture is irrelevant here. The format is always the same, regardless of the current culture.
So what you want to use is:
Console.WriteLine("{0:0,0.00}", d);
Then the output is:
4434 Type of: System.Double
4.434,00
I need to parse the string "1.2345E-02" (a number expressed in exponential notation) to a decimal data type, but Decimal.Parse("1.2345E-02") simply throws an error
It is a floating point number, you have to tell it that:
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
It works if you specify NumberStyles.Float:
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345
I'm not entirely sure why this isn't supported by default - the default is to use NumberStyles.Number, which uses the AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint, and AllowThousands styles. Possibly it's performance-related; specifying an exponent is relatively rare, I suppose.
In addition to specifying the NumberStyles I would recommend that you use the decimal.TryParse function such as:
decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
// do something in case it fails?
}
As an alternative to NumberStyles.Any you could use a specific set if you're certain of your formats. e.g:
NumberStyles.AllowExponent | NumberStyles.Float
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Be cautious about the selected answer: there is a subtility specifying System.Globalization.NumberStyles.Float in Decimal.Parse which could lead to a System.FormatException because your system might be awaiting a number formated with ',' instead of '.'
For instance, in french notation, "1.2345E-02" is invalid, you have to convert it to "1,2345E-02" first.
In conclusion, use something along the lines of:
Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
The default NumberStyle for decimal.Parse(String) is NumberStyles.Number, so if you just want to add the functionality to allow exponents, then you can do a bitwise OR to include NumberStyles.AllowExponent.
decimal d = decimal
.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
I've found that passing in NumberStyles.Float, in some cases, changes the rules by which the string is processed and results in a different output from NumberStyles.Number (the default rules used by decimal.Parse).
For example, the following code will generate a FormatException in my machine:
CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5", NumberStyles.Float, culture); // FormatException thrown here
I'd recommend using the input NumberStyles.Number | NumberStyles.AllowExponent, as this will allow exponential numbers and will still process the string under the decimal rules.
CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5",NumberStyles.Number | NumberStyles.AllowExponent, culture); // Does not generate a FormatException
To answer the poster's question, the right answer should instead be:
decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);
Warning about using NumberStyles.Any:
"6.33E+03" converts to 6330 as expected. In German, decimal points are represented by commas, but 6,33E+03 converts to 633000! This is a problem for my customers, as the culture that generates the data is not known and may be different than the culture that is operating on the data. In my case, I always have scientific notation, so I can always replace comma to decimal point before parsing, but if you are working with arbitrary numbers, like pretty-formatted numbers like 1,234,567 then that approach doesn't work.
You don't need to replace the dots (respectively the commas) just specify the input IFormatProvider:
float d = Single.Parse("1.27315", System.Globalization.NumberStyles.Float, new CultureInfo("en-US"));
float d = Single.Parse("1,27315", System.Globalization.NumberStyles.Float, new CultureInfo("de-DE"));
If you want to check and convert the exponent value use this
string val = "1.2345E-02";
double dummy;
bool hasExponential = (val.Contains("E") || val.Contains("e")) && double.TryParse(val, out dummy);
if (hasExponential)
{
decimal d = decimal.Parse(val, NumberStyles.Float);
}
Hope this helps someone.