web-dev-qa-db-ja.com

適切なcultureinfoで文字列をdoubleに変換する方法

データベースには、DataTypeとDefaultValueを格納する2つのnvarcharフィールドがあり、DataType Doubleと値は英語形式で65.89875になっています。

ここで、選択したブラウザーの言語形式(英語の65.89875はドイツ語の65,89875として表示されるはずです)に従ってユーザーに値を表示するようにします。ユーザーがドイツ語の形式から65,89875(英語では65.89875相当)に編集し、他のユーザーが英語のブラウザーから表示する場合、6589875になります。

これは、データベースのnvarchar列に65,89875として格納されていたためです。英語のカルチャを使用して変換すると、,は、ドイツ語の10進演算子である区切り文字として使用します。

すべてのブラウザでこれを機能させるにはどうすればよいですか?

35
Vinay Pandey

データベースに保存されるデータに使用する単一のロケールを定義する必要があります。不変のカルチャはまさにこの目的のためにあります。

ネイティブタイプへの変換を表示してから、ユーザーのカルチャに合わせてフォーマットします。

例えば。表示する:

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, NumberStyles.Any, userCulture, out value)) {
  // Error...
}
string forDB = value.ToString(CultureInfo.InvariantCulture);

PS。ほとんどの場合、データと一致するデータ型を持つ列を使用することはさらに良いことは言うまでもありません(ただし、レガシーが適用される場合もあります)。

61
Richard

私は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"));
3
user2738678

UIカルチャを任意に変更できますが、次のように番号区切り記号を変更する必要があります。

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を示す2番目のパラメーターを持つこともできます。これをSystem.Globalization.CultureInfo InvariantCultureに設定すると、結果は常に同じになります。

1
Bolle

FormatProviders を使用して、ユーザーが指定した値をdoubleに変換し、nvarcharとして再度格納できます。 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);
}
1
tafa

私は何年も前からツールベルトにこの関数を持っています(すべての関数名と変数名は乱雑で、スペイン語と英語が混ざっています。ごめんなさい)。

ユーザーが,および.小数点を分離し、両方の記号が使用されている場合に最善を尽くそうとします。

    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
0
Eduardo Molteni