I have to read a .txt and display it. The double values in the data are written with a ".". When I have german language enabled it doesn't interpret it as a comma. Now I tried to check if the language is set to German and replace all the "." with a ",". The values are stored in an array named "_value" but it doesn't work. Here is the code:
if ((System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName) == "de")
{
for (int i = 0; i < _value.Length; i++)
{
String temp_var = Convert.ToString(_value[i]);
temp_var.Replace(".", ",");
_value[i] = Convert.ToDouble(temp_var);
}
}
Instead of checking the language, you can also supply the culture with which the conversion is done:
// Convert string to double from the invariant culture, which treats "." as decimal:
double d = Convert.ToDouble(_value[i], CultureInfo.InvariantCulture);
// Convert double to string using the current culture, which may happen to be German and uses a ",":
string s = Convert.ToString(d);
// Or convert double to string using the specific German culture:
string s = Convert.ToString(d, new CultureInfo("de-DE"));
What I don't understand is that apparently the _value array is already a double[] - so these changes will have to be made earlier in your code, where the conversion from string to double actually happens.
Any reason you don't just set the appropriate culture temporarily?
using System.Threading;
using System.Globalization;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Related
I have two nvarchar fields in a database to store the DataType and DefaultValue, and I have a DataType Double and value as 65.89875 in English format.
Now I want the user to see the value as per the selected browser language format (65.89875 in English should be displayed as 65,89875 in German). Now if the user edits from German format to 65,89875 which is 65.89875 equivalent in English, and the other user views from an English browser it comes as 6589875.
This happens because in the database it was stored as 65,89875 in the nvarchar column and when converted using English culture it becomes 6589875 since it considers , as a separator which is a decimal operator for German.
How do I get this working for all the browsers?
You need to define a single locale that you will use for the data stored in the database, the invariant culture is there for exactly this purpose.
When you display convert to the native type and then format for the user's culture.
E.g. to display:
string fromDb = "123.56";
string display = double.Parse(fromDb, CultureInfo.InvariantCulture).ToString(userCulture);
to store:
string fromUser = "132,56";
double value;
// Probably want to use a more specific NumberStyles selection here.
if (!double.TryParse(fromUser, NumberStyles.Any, userCulture, out value)) {
// Error...
}
string forDB = value.ToString(CultureInfo.InvariantCulture);
PS. It, almost, goes without saying that using a column with a datatype that matches the data would be even better (but sometimes legacy applies).
You can change your UI culture to anything you want, but you should change the number separator like this:
CultureInfo info = new CultureInfo("fa-IR");
info.NumberFormat.NumberDecimalSeparator = ".";
Thread.CurrentThread.CurrentCulture = info;
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
With this, your strings converts like this: "12.49" instead of "12,49" or "12/49"
Convert.ToDouble(x) can also have a second parameter that indicates the CultureInfo and when you set it to
System.Globalization.CultureInfo InvariantCulture
the result will allways be the same.
I took some help from MSDN, but this is my answer:
double number;
string localStringNumber;
string doubleNumericValueasString = "65.89875";
System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint;
if (double.TryParse(doubleNumericValueasString, style, System.Globalization.CultureInfo.InvariantCulture, out number))
Console.WriteLine("Converted '{0}' to {1}.", doubleNumericValueasString, number);
else
Console.WriteLine("Unable to convert '{0}'.", doubleNumericValueasString);
localStringNumber =number.ToString(System.Globalization.CultureInfo.CreateSpecificCulture("de-DE"));
You can convert the value user provides to a double and store it again as nvarchar, with the aid of FormatProviders. CultureInfo is a typical FormatProvider. Assuming you know the culture you are operating,
System.Globalization.CultureInfo EnglishCulture = new System.Globalization.CultureInfo("en-EN");
System.Globalization.CultureInfo GermanCulture = new System.Globalization.CultureInfo("de-de");
will suffice to do the neccesary transformation, like;
double val;
if(double.TryParse("65,89875", System.Globalization.NumberStyles.Float, GermanCulture, out val))
{
string valInGermanFormat = val.ToString(GermanCulture);
string valInEnglishFormat = val.ToString(EnglishCulture);
}
if(double.TryParse("65.89875", System.Globalization.NumberStyles.Float, EnglishCulture, out val))
{
string valInGermanFormat = val.ToString(GermanCulture);
string valInEnglishFormat = val.ToString(EnglishCulture);
}
Use InvariantCulture. The decimal separator is always "." eventually you can replace "," by "."
When you display the result , use your local culture. But internally use always invariant culture
TryParse does not allway work as we would expect There are change request in .net in this area:
https://github.com/dotnet/runtime/issues/25868
I have this function in my toolbelt since years ago (all the function and variable names are messy and mixing Spanish and English, sorry for that).
It lets the user use , and . to separate the decimals and will try to do the best if both symbols are used.
Public Shared Function TryCDec(ByVal texto As String, Optional ByVal DefaultValue As Decimal = 0) As Decimal
If String.IsNullOrEmpty(texto) Then
Return DefaultValue
End If
Dim CurAsTexto As String = texto.Trim.Replace("$", "").Replace(" ", "")
''// You can probably use a more modern way to find out the
''// System current locale, this function was done long time ago
Dim SepDecimal As String, SepMiles As String
If CDbl("3,24") = 324 Then
SepDecimal = "."
SepMiles = ","
Else
SepDecimal = ","
SepMiles = "."
End If
If InStr(CurAsTexto, SepDecimal) > 0 Then
If InStr(CurAsTexto, SepMiles) > 0 Then
''//both symbols was used find out what was correct
If InStr(CurAsTexto, SepDecimal) > InStr(CurAsTexto, SepMiles) Then
''// The usage was correct, but get rid of thousand separator
CurAsTexto = Replace(CurAsTexto, SepMiles, "")
Else
''// The usage was incorrect, but get rid of decimal separator and then replace it
CurAsTexto = Replace(CurAsTexto, SepDecimal, "")
CurAsTexto = Replace(CurAsTexto, SepMiles, SepDecimal)
End If
End If
Else
CurAsTexto = Replace(CurAsTexto, SepMiles, SepDecimal)
End If
''// At last we try to tryParse, just in case
Dim retval As Decimal = DefaultValue
Decimal.TryParse(CurAsTexto, retval)
Return retval
End Function
I need to keep culture when converting double to string and also round to only one decimal place.
Converting double to string with culture:
((12275454.8).ToString("N", new CultureInfo("sl-SI")));
Gives output:
12.275.454,80
Converting double to string with only one decimal:
string.Format("{0:F1}",12275454.8)
Gives output:
12275454.8
The second output is without culture, the first output is not rounded to one decimal place. How to combine both methods?
Just use the format string of your second example in your first example, i.e.:
((12275454.8).ToString("N1", new CultureInfo("sl-SI")));
Edit: Changed format from F1 to N1 as per request. The difference between both is that N additionally uses thousands separators, whereas F does not. For details see https://msdn.microsoft.com/en-US/library/dwhawy9k(v=vs.110).aspx
You can set "sl-SI" culture as a default one:
using System.Threading;
...
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("sl-SI");
string test = string.Format("{0:F1}",12275454.8);
Add try..finally if you want "sl-SI" culture for a block of code only:
var savedCulture = Thread.CurrentThread.CurrentCulture;
try {
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("sl-SI");
// Let's work with "sl-SI" for a while
string test = string.Format("{0:F1}",12275454.8);
...
}
finally {
Thread.CurrentThread.CurrentCulture = savedCulture;
}
The value that extracted from the application is in string format for ex. "$0.38". So, I segregated each character in the given string using IsDigit then appended them together using string builder. The digit can also be alphanumeric like "12,365.23 AS". Is there a way to recover only numeric part (along with the decimal) from the given string.
But Output I receive is "38" instead of "0.38". I also want to compare that the given string value lies between the upperLimit and lowerLimit provided.
Please let me know how to proceed with the same.
string Value = "$0.38";
int upperLimit = 2500;
int lowerLimit = 50000;
StringBuilder sb = new StringBuilder();
//sb.Append(someString);
foreach (char amin in Value)
{
if (System.Char.IsDigit(amin))
{
sb.Append(amin);
}
}
int compareVal = Convert.ToInt32(sb.ToString());
Console.WriteLine("value for comparision" + " " + compareVal);
The best way is using one of the overloads of decimal.Parse:
string Value = "$0.38";
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
decimal dd=decimal.Parse(Value, System.Globalization.NumberStyles.AllowCurrencySymbol|System.Globalization.NumberStyles.AllowDecimalPoint,culture);
Note the use of NumberStyles enum.That way you can control exaclty the parsing.
There are two reasons why you will get 38:
StringBuilder looks like "038", since "." is not a digit (just like "$").
Convert.ToInt32(...) returns an integer which doesn't allow decimal digits.
The better data type for currencies is decimal, a high precision floating point data type so to say.
Try
var amount = decimal.Parse(Value , NumberStyles.Currency)
var isInLimit = upperLimit <= amount && amount <= lowerLimit; // i guess you swapped upper and lower limit btw. ;)
instead.
Edit
In order to use the NumberStyles-Enumeration, you will have to use tha correct namespace in your file:
using System.Globalization;
You are omitting the decimal point and you are not using a decimal data type to hold the converted value. The real way to go is to convert the currency string to a decimal number:
CultureInfo usCulture = new CultureInfo("en-US)";
decimal amount = decimal.Parse(Value, NumberStyles.Currency, usCulture);
You can then perform a proper numeric comparison:
if (amount <= upperLimit && amount >= lowerLimit)
....
I first marked the question as a duplicate, but then changed my mind. I still think it is very much related to: Convert any currency string to double
I have an incoming source of string values representing double values with "." and "," delimiter and my program would run on PCs with different settings of delimiter ("," or ",")
Which way can I convert it with single line without trying first convert ".", then if fail, try ","?
I tried some combinations like that:
string dot_val = "1.12";
string non_dot_val = "1,12";
double dot_double = 0, non_dot_double = 0;
bool dot_res = double.TryParse(dot_val, NumberStyles.Any, CultureInfo.CurrentCulture, out dot_double);
bool non_dot_res = double.TryParse(non_dot_val, NumberStyles.Number | NumberStyles.AllowCurrencySymbol, CultureInfo.CurrentCulture, out non_dot_double);
But one of the attempts to convert is always fail.
If tell it shortly, I need an universal function to convert "." or "," delimited double values into double
Well, the current culture tells you whether . or , is the decimal separator. If you want your function to parse both formats, you need to pass in a culture that has the respective separator. In your example:
public double UniveralParse(string value)
{
double result;
// If we can not parse the "." format...
if (!double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result))
// And also can not parse the "," format...
if (!double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("de-DE"), out result))
// we throw an exception
throw new ArgumentException("value is not in expected format!");
// Otherwise we can return the value
return result;
}
The easiest way is to replace ',' by '.' and parse the result using the invariant culture setting:
double.TryParse(
dot_val.Replace(',','.'),
NumberStyles.Any,
CultureInfo.InvariantCulture,
out dot_double);
The only limitation of this is that you shouldn't have grouping in your number (like 123,000.45)
I need convert a String to a decimal in C#, but this string have different formats.
For example:
"50085"
"500,85"
"500.85"
This should be convert for 500,85 in decimal. Is there is a simplified form to do this convertion using format?
Some cultures use a comma to indicate the floating point. You can test this with the following code on an aspx page:
var x = decimal.Parse("500,85");
Response.Write(x + (decimal)0.15);
This gives the answer 501 when the thread culture has been set to a culture that uses the comma as floating point. You can force this like so:
var x = decimal.Parse("500,85", new NumberFormatInfo() { NumberDecimalSeparator = "," });
While decimal.Parse() is the method you are looking for, you will have to provide a bit more information to it. It will not automatically pick between the 3 formats you give, you will have to tell it which format you are expecting (in the form of an IFormatProvider). Note that even with an IFormatProvider, I don't think "50085" will be properly pulled in.
The only consistent thing I see is that it appears from your examples that you always expect two decimal places of precision. If that is the case, you could strip out all periods and commas and then divide by 100.
Maybe something like:
public decimal? CustomParse(string incomingValue)
{
decimal val;
if (!decimal.TryParse(incomingValue.Replace(",", "").Replace(".", ""), NumberStyles.Number, CultureInfo.InvariantCulture, out val))
return null;
return val / 100;
}
This will work, depending on your culture settings:
string s = "500.85";
decimal d = decimal.Parse(s);
If your culture does not by default allow , instead of . as a decimal point, you will probably need to:
s = s.Replace(',','.');
But will need to check for multiple .'s... this seems to boil down to more of an issue of input sanitization. If you are able to validate and sanitize the input to all conform to a set of rules, the conversion to decimal will be a lot easier.
Try this code below:
string numValue = "500,85";
System.Globalization.CultureInfo culInfo = new System.Globalization.CultureInfo("fr-FR");
decimal decValue;
bool decValid = decimal.TryParse(numValue, System.Globalization.NumberStyles.Number, culInfo.NumberFormat, out decValue);
if (decValid)
{
lblDecNum.Text = Convert.ToString(decValue, culInfo.NumberFormat);
}
Since I am giving a value of 500,85 I will assume that the culture is French and hence the decimal separator is ",". Then decimal.TryParse(numValue, System.Globalization.NumberStyles.Number, culInfo.NumberFormat,out decValue);
will return the value as 500.85 in decValue. Similarly if the user is English US then change the culInfo constructor.
There are numerous ways:
System.Convert.ToDecimal("232.23")
Double.Parse("232.23")
double test;
Double.TryParse("232.23", out test)
Make sure you try and catch...
This is a new feature called Digit Grouping Symbol.
Steps:
Open Region and Language in control panel
Click on Additional setting
On Numbers tab
Set Digit Grouping Symbol as custom setting.
Change comma; replace with (any character as A to Z or {/,}).
Digit Grouping Symbol=e;
Example:
string checkFormate = "123e123";
decimal outPut = 0.0M;
decimal.TryParse(checkFormate, out outPut);
Ans: outPut=123123;
Try This
public decimal AutoParse(string value)
{
if (Convert.ToDecimal("3.3") == ((decimal)3.3))
{
return Convert.ToDecimal(value.Replace(",", "."));
}
else
{
return Convert.ToDecimal(value.Replace(".", ","));
}
}