【问题标题】:Convert string to double do not respect current number decimal separator将字符串转换为双精度不考虑当前数字小数分隔符
【发布时间】:2014-10-09 11:09:44
【问题描述】:

我正在尝试将表示双精度的字符串从不变的文化转换为当前文化表示中的双精度,我关心的是如何让新的双精度表示使用当前文化的当前数字小数分隔符。

我使用下面的代码进行转换:

public static double ConvertToDouble(this object inputVal, bool useCurrentCulture = false)
{
    string currentSep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    string invariantSep = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
    if (inputVal.GetType() == typeof(string))
    {
        if (!currentSep.Equals(invariantSep))
        {
            inputVal = (inputVal as string).Replace(invariantSep, currentSep);
        }
    }
    if (useCurrentCulture)
        return Convert.ToDouble(inputVal, CultureInfo.CurrentCulture);
    else
        return Convert.ToDouble(inputVal);
}

但上面的代码总是给我一个带“.”的双精度,尽管我使用 CurrentCulture 例如法语应该给我一个带逗号 (",") 的双精度。

非常感谢任何提示。

FreeDev

【问题讨论】:

  • 如果要将字符串转换为双精度,为什么扩展完全接受对象?此外,在我看来,object 的扩展是一个坏主意。你用一种几乎永远不会使用的方法污染了智能感知。

标签: c#-4.0


【解决方案1】:

但是上面的代码总是给我一个带有“。”的双精度。作为 NumberDecimalSeparator

不,它返回一个doubledouble 只是一个数字。它没有NumberDecimalSeparator... 只有一种文化,并且仅在转换为字符串或从字符串转换时应用。谈论 double 的分隔符就像谈论 int 是十进制还是十六进制 - 没有这样的概念。 0x10 和 16 是相同的值,用相同的位表示。

不清楚您要做什么,但了解文本表示中存在的内容与数据值本身固有的内容之间的区别至关重要。在解析或格式化时,您应该关心分隔符 - 但在解析为 double 之后,该信息就消失了。

【讨论】:

  • 感谢 Jhon 的评论,但这只是一个例子来说明为什么在当前文化中具有 NumberDecimalSeparator ="," 的转换会给出带有 "." 的双精度,你有什么想法吗?
  • @FreeDev:你似乎没有理解我的意思。没有“带有“.”的双精度词”这样的东西。只有一个double。点仅在您将其转换为文本时才会显示 - 您应该在此处决定使用哪种格式。
  • 即使没有 useCurrentCulture 作为参数,方法 ConvertToDoubleInvariant 也会出现矛盾。正如 Jon 试图指出的那样,double 没有文化。
  • @TimSchmelter:我将“不变”部分解释为“使用不变的文化来执行转换”,这是有道理的。我看到问题中的方法名称现在已更改...
【解决方案2】:

根据 cmets 和您的问题,我猜您实际上想使用 InvariantCulture 或当前文化将 string 转换为 double。然后应该将此双精度转换为由当前文化日期时间格式信息格式化的字符串(如NumberDecimalSeparator)。

所以这个方法应该做两件事:

  1. 将字符串解析为双精度
  2. 将双精度转换为字符串

public static string ConvertToFormattedDouble(this string inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
    if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
    if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;
    if (sourceFormatProvider == targetFormatProvider)
        return inputVal; // or exception?

    double d;
    bool isConvertable = double.TryParse(inputVal, NumberStyles.Any, sourceFormatProvider, out d);
    if (isConvertable)
        return d.ToString(targetFormatProvider);
    else
        return null; // or whatever
}

你可以这样使用:

string input = "1234.567";
string output = input.ConvertToFormattedDouble();  // "1234,567"

请注意,我扩展了字符串而不是对象。在我看来,对象的扩展是一个坏主意。你用一种几乎永远不会使用的方法污染了智能感知(尽管它也适用于string)。


更新

如果您真的想走这条路并使用object 的扩展程序,它支持任何类型的数字作为(盒装)对象或字符串,您可以试试这个扩展程序:

public static string ConvertToFormattedDouble(this object inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
    if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
    if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;

    if (inputVal is string)
    {
        double d;
        bool isConvertable = double.TryParse((string)inputVal, NumberStyles.Any, sourceFormatProvider, out d);
        if (isConvertable)
            return d.ToString(targetFormatProvider);
        else
            return null;
    }
    else if (IsNumber(inputVal))
    {
        decimal d = Convert.ToDecimal(inputVal, sourceFormatProvider);
        return Decimal.ToDouble(d).ToString(targetFormatProvider);
    }
    else
        return null;
}

public static bool IsNumber(this object value)
{
    return value is sbyte
            || value is byte
            || value is short
            || value is ushort
            || value is int
            || value is uint
            || value is long
            || value is ulong
            || value is float
            || value is double
            || value is decimal;
}

用法:

object input = 1234.56745765677656578d;
string output = input.ConvertToFormattedDouble();  // "1234,56745765678"

【讨论】:

  • 我使用了一个对象来扩展,因为我会用这个方法来处理十进制,字符串..我需要格式化结果但是类型是双1234,567跨度>
  • 您的解决方案很好地指导了我,在我使用更新的解决方案并在最后一天验证了一些结果之后,答案是 (y)。非常感谢。
猜你喜欢
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 2011-08-11
相关资源
最近更新 更多