Как преобразовать строку в удвоение с правильной cultureinfo
У меня есть два поля nvarchar в базе данных для хранения DataType и DefaultValue, и у меня есть DataType Double и значение как 65.89875 в английском формате.
Теперь я хочу, чтобы пользователь видел значение в соответствии с выбранным языковым форматом браузера (65,89875 на английском языке должно отображаться как 65,89875 на немецком языке). Теперь, если пользователь редактирует с немецкого формата на 65 89875, что эквивалентно 65 89875 на английском языке, и другие пользовательские просмотры из английского браузера, это будет 6589875.
Это происходит потому, что в базе данных он хранится как 65 89875 в столбце nvarchar, а при преобразовании с использованием английской культуры он становится 65 89875, так как он считает ,
в качестве разделителя, который является десятичным оператором для немецкого языка.
Как мне заставить это работать для всех браузеров?
7 ответов
Вам нужно определить одну локаль, которую вы будете использовать для данных, хранящихся в базе данных, именно для этой цели существует инвариантная культура.
Когда вы выводите на экран конвертировать в собственный тип, а затем форматировать для культуры пользователя.
Например, для отображения:
string fromDb = "123.56";
string display = double.Parse(fromDb, CultureInfo.InvariantCulture).ToString(userCulture);
хранить:
string fromUser = "132,56";
double value;
// Probably want to use a more specific NumberStyles selection here.
if (!double.TryParse(fromUser, userCulture, NumberStyles.Any, out value)) {
// Error...
}
string forDB = value.ToString(CultureInfo.InvariantCulture);
PS. Почти само собой разумеется, что использование столбца с типом данных, который соответствует данным, было бы даже лучше (но иногда применяется устаревшее).
Вы можете изменить свою культуру пользовательского интерфейса на что угодно, но вы должны изменить разделитель чисел следующим образом:
CultureInfo info = new CultureInfo("fa-IR");
info.NumberFormat.NumberDecimalSeparator = ".";
Thread.CurrentThread.CurrentCulture = info;
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
При этом ваши строки преобразуются следующим образом: "12,49" вместо "12,49" или "12/49"
Convert.ToDouble(x) также может иметь второй параметр, который указывает CultureInfo, и когда вы устанавливаете его в System.Globalization.CultureInfo InvariantCulture, результат всегда будет одинаковым.
Я получил некоторую помощь от MSDN, но это мой ответ:
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"));
Вы можете преобразовать значение, предоставленное пользователем, в double и сохранить его снова как nvarchar с помощью FormatProviders. CultureInfo - это типичный FormatProvider. Предполагая, что вы знаете культуру, с которой вы работаете,
System.Globalization.CultureInfo EnglishCulture = new System.Globalization.CultureInfo("en-EN");
System.Globalization.CultureInfo GermanCulture = new System.Globalization.CultureInfo("de-de");
будет достаточно, чтобы сделать необходимые преобразования, как;
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);
}
Используйте InvariantCulture. Десятичный разделитель всегда "." в конце концов вы можете заменить "," на "." При отображении результата используйте местную культуру. Но внутренне используйте всегда инвариантную культуру
TryParse не всегда работает так, как мы ожидали. В этой области есть запрос на изменение в .net:
У меня есть эта функция в моем наборе инструментов с много лет назад (все имена функций и переменных являются грязными и смешивают испанский и английский, извините за это).
Это позволяет пользователю использовать ,
а также .
разделить десятичные дроби и постараемся сделать все возможное, если используются оба символа.
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