How to convert string to double with proper cultureinfo
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开发者_JAVA百科 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
精彩评论