如何让Decimal.TryParse解析0.0?

时间:2010-01-26 22:13:12

标签: c# .net

有没有办法让Decimal.TryParse将字符串值“0.0”或“00.00”或“000.000”解析为0?

我已尝试将NumberStyles设置为Any。

10 个答案:

答案 0 :(得分:13)

使用InvariantCulture,decimal.TryParse会成功地将所有这些字符串解释为零。这段代码,例如:

decimal num = 66;
foreach (var str in new string[] { "0.0", "00.00", "000.000" })
{
    if (!decimal.TryParse(str, out num))
    {
        Console.WriteLine( "fail" );
    }
    Console.WriteLine(num);
}

生成此输出:

0.0
0.00
0.000

也许,问题是打印值,而不是解析值?如果是这种情况,只需使用一个格式字符串,指定小数位是可选的。

Console.WriteLine( num.ToString( "#0.#" ) );

可生产

0
0
0

答案 1 :(得分:5)

  

有没有办法让Decimal.TryParse将字符串值"0.0""00.00""000.000"解析为0?

我正在解释你的问题。假设我接受字符串"0.0""00.00""000.000"请求Decimal.TryParse来解析它们。当我将结果十进制写入控制台时,我分别看到0.00.000.000。有没有办法让Decimal.TryParse在所有这些情况下返回decimal,并将0写入控制台?

没有。想想为什么会这样。 Decimal类型代表精确数字;在某些圈子中,0.00被认为比0.0更精确,0Decimal.TryParse更精确。如果Decimal被截断,那么精度高于static char[] whitespaceAndZero = new[] { ' ', '\t', '\r', '\n', '\u000b', // vertical tab '\u000c', // form feed '0' }; static string TrimEndWhitespaceAndZeros(string s) { return s.Contains('.') ? s.TrimEnd(whitespaceAndZero) : s; } static bool TryParseAfterTrim(string s, out decimal d) { return Decimal.TryParse(TrimEndWhiteSpaceAndZeros(s), out d); } 类型对于这些目的无用。

也就是说,在调用parse之前修剪尾随的零很容易:

string s = "0.00";
decimal d;
TryParseAfterTrim(s, out d);
Console.WriteLine(d);

用法:

0

输出:

'.'

请注意,上述内容仅显示了如何解决问题的关键。您可以自行决定是否以及如何处理本地化问题。至少,在将其投入生产之前,您应该考虑将CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator替换为TryParseAfterTrim。您应该考虑使用与Decimal.TryParse相同的参数列表来重载bool TryParseAfterTrim( string s, NumberStyle style, IFormatProvider provider, out decimal result ) 。那就是:

{{1}}

答案 2 :(得分:3)

在.NET 1.1中引入了以十进制值保留尾随零,以更严格地符合ECMA CLI规范。请参阅this answer to a similar question

虽然原始问题仅限于在解析字符串时删除尾随零,但我认为理解为什么以及在十进制值的内部表示中保留尾随零的情况非常重要。

由于以下结果,尾随零可以显示为十进制值:

a)解析具有尾随零的输入,如原始帖子或

b)作为计算的结果。例如:乘以十进制值1.2 * 1.5给出1.80的结果:这是因为将两个精确到一个小数位的值相乘得到的结果精确到两个小数位 - 因此即使第二个小数位也是如此它的值为零。

如何处理内部十进制表示中的尾随零?通常什么都不做:你可以在输出上格式化到你想要的小数位数,这样它们就不会受到伤害。

十进制主要用于财务计算,并且通常希望保留尾随零,以便舍入到最接近的分数的数量表示为1.20而不是1.2。通常在使用小数时,您将按固定精度工作(可能是零售应用中最接近的分数,或者在计算手机使用费时最接近百分之一分)。因此,您的应用程序逻辑将使用显式舍入规则明确地舍入到固定数量的小数,例如:使用MidpointRounding.AwayFromZero汇总到最接近的分数的税收计算:

decimal price = 1.20M;   
decimal taxRate = 0.175; // 17.5%
decimal taxAmount = Math.Round(price*taxRate, 2, 
                      MidpointRounding.AwayFromZero);

如果你没有以这种方式处理固定数量的小数,你可能会考虑是否应该使用double而不是decimal。

尽管如此,有时可能需要删除尾随零,同时保留所有有效数字。 AFAIK,没有内置的方法。

如果您需要这样做,基本的解决方案是使用标准格式字符串“G28”格式化为字符串(相当于自定义格式字符串“0。############ ################“),然后将结果解析回小数。

删除尾随零而不转换为字符串/从字符串转换的替代方法(可能更快,但我没有测量它)是使用Math.Round - 例如以下方法:

    static decimal RemoveTrailingZeroes(decimal value)
    {
        const int MaxDecimals = 28;
        decimal roundedValue;
        for (int decimals = 0; decimals < MaxDecimals; decimals++)
        {
            roundedValue = Math.Round(value, decimals);
            if (value == roundedValue) return roundedValue;
        }
        return value;
    }

答案 3 :(得分:2)

什么不起作用?这对我来说很好(用“0.0”,“00.00”和“000.000”测试):

decimal d;
if (decimal.TryParse("0.0", NumberStyles.Any, CultureInfo.InvariantCulture, out d))
{
    // use d
}

答案 4 :(得分:2)

我谦卑地提交这个解决方案:

    decimal processedValue = value == 0 ? 0 : value;

这不能胜任这个工作吗?

这是一个完整的例子:

string valueString = "0.000";
decimal value;
bool isValid = decimal.TryParse(valueString, out value);
if (isValid)
{
    decimal processedValue = value == 0 ? 0 : value;
    System.Diagnostics.Debug.Print("value: {0}, processedValue: {1}", value, processedValue);
}

答案 5 :(得分:1)

//输出0给出0.0作为字符串虽然......

 decimal d;

 decimal.TryParse("0.0", out d);

 string s = String.Format("{0:0}", d);

答案 6 :(得分:1)

为什么不使用int.TryParse?或double.TryParse?

答案 7 :(得分:0)

在Console.Writeline中,应用字符串格式以保持双零精度。

答案 8 :(得分:0)

我明白你的意思了。以下代码:

decimal number = -1.0M;
bool res1 = decimal.TryParse("0.0", out number);
Console.WriteLine(string.Format("number = {0}", number));
number = -1.0M;
bool res2 = decimal.TryParse("00.00", out number);
Console.WriteLine(string.Format("number = {0}", number));
number = -1.0M;
bool res3 = decimal.TryParse("000.000", out number);
Console.WriteLine(string.Format("number = {0}", number));
number = -1.0M;
bool res4 = decimal.TryParse("0000.0000", out number);
Console.WriteLine(string.Format("number = {0}", number));

打印:

number = 0.0
number = 0.00
number = 0.000
number = 0.0000

因此输入会影响输出。但是,使用调试器检查number的值在工具提示和本地窗口中显示“0”,表示这是格式问题,而不是存储值的基本问题。

然而,正如其他人所说,在转换之前修剪尾随零(和小数点)。

答案 9 :(得分:0)

在小数点后除去尾随零的一种方法是用十进制消除它们。

蛮力方式将干扰小数的内部结构:

public static Decimal TrimFractionZeros(this Decimal zahl)
{
  int[] bits = decimal.GetBits(zahl);
  byte decimals = (Byte)(bits[3] >> 16);
  bool negativ = (bits[3] >> 31) != 0;
  zahl = new decimal(bits[0], bits[1], bits[2], false, 0);
  while ((decimals > 0) && ((zahl % 10) == 0))
  {
    zahl /= 10;
    decimals--;
  }
  bits = decimal.GetBits(zahl);
  return new decimal(bits[0], bits[1], bits[2], negativ, decimals);
}

不漂亮,不快,但它会将“0.000”的内部表示更改为十进制的“0”。