如何将C#的十进制数格式化以去除多余的0?

50

我想将一个包含一些无意义的0的十进制数字符串进行格式化,使这些无意义的0消失,应该如何进行格式化?

string.Format("{0}", 1100M);
string.Format("{0}", 1100.1M);
string.Format("{0}", 1100.100M);
string.Format("{0}", 1100.1000M);

显示:

1100
1100.1
1100.100
1100.1000

但我希望它是这样的:

1100
1100.1
1100.1
1100.1

供参考,以下是与此问题本质相同的其他问题,我通过这里的答案找到了它们:


1002.231只是一个例子吗?也就是说,你想让1.12000变成1.12还是1.120? - n8wrl
1
请注意,如果您想要一个十进制值,应该使用一个,例如1100.1000m。请注意,“m”表示“十进制字面量”。 - Jon Skeet
@Jon:谢谢,我也注意到了并去修复了它,当我回来时发现你的评论已经等着我了。速度真快... ;) - Scott Stafford
@n8wrl:这只是一个例子,是的,我更新了更多的例子。 - Scott Stafford
11个回答

85

您可以使用通用格式说明符 ("G")ToString()方法来达到所需的结果。当指定精度使用此格式字符串时,尾随零将被截断。要在任何情况下都避免四舍五入,您需要将精度设置为十进制数的最大值(29)。

生成您想要的结果的代码行是number.ToString("G29"),其中number是您的原始十进制数。

请注意,小于0.0001的任何数字都将转换为科学计数法。有关此格式化程序的详细信息,请参见上面的参考链接。


5
我认为这是对这个问题最好的解决方案。 - Wegged
2
Concur -- 答案已更改。谢谢,@Herohtar。 - Scott Stafford
2
警告:小心像0.000001这样的值。G29格式将以最短可能的方式呈现它们,因此会切换到指数符号表示法。string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))将给出"1E-08"作为结果。Credit goes to Konrad here: https://dev59.com/um855IYBdhLWcg3wHweH#4525983 - Doug S
答案已更新,附上正确的链接和最新信息。 - Herohtar
1
G29不是必需的。对于十进制数,“G0”等同于“G29”。 - statler
显示剩余4条评论

23
string s = d.ToString("0.#############################");

4

2
但我不知道它末尾有三个小数点,我只是举例而已。我会让问题更清晰明了。 - Scott Stafford

4

它们并不一定是没有意义的 - 它们在计算过程中表明了精度。小数保持其精度级别,而不是被归一化。

这个答案中,我有一些代码可以返回一个归一化的值 - 你可以使用它,然后格式化结果。例如:

using System;
using System.Numerics;

class Test
{
    static void Display(decimal d)
    {
        d = d.Normalize(); // Using extension method from other post
        Console.WriteLine(d);
    }

    static void Main(string[] args)
    {
        Display(123.4567890000m); // Prints 123.456789
        Display(123.100m);        // Prints 123.1
        Display(123.000m);        // Prints 123
        Display(123.4567891234m); // Prints 123.4567891234
    }
}

我认为大多数格式字符串的方法都会失败。我猜想一个由" 0."和28个#字符组成的格式字符串可能会起作用,但它看起来很丑陋...


1
看起来你的解决方案只适用于 .Net 4.0。 - Gabe
@Gabe:除非你使用第三方 BigInteger 实现,否则是的。另一方面,它非常低效。 另外,它的优点是能够正常工作 :) - Jon Skeet

4

与大家建议使用G格式说明符不同,我建议采用以下方法来保留千分位分隔符和小数点,同时删除额外的尾随零:

{0:#,#.##}

这种格式的结果在大多数情况下比G格式好得多:
String.Format("{0:#,#.##}",25/2.4);
10.42

String.Format("{0:#,#.##}",1000000);
1,000,000

String.Format("{0:#,#.##}",1000000.3600000);
1,000,000.36

G 指定符无法处理所有可能的组合:

String.Format("{0:G29}",25/2.4);
10.416666666666668

String.Format("{0:G2}",25/2.4);
10

String.Format("{0:G29}",1000000.3600000);
1000000.36

String.Format("{0:G2}",1000000.3600000);
1E+06

3
怎么样:
string FormatDecimal(decimal d)
{
    const char point = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0];
    string s = d.ToString();
    // if there's no decimal point, there's nothing to trim
    if (!s.Contains(point) == -1)
        return s;
    // trim any trailing 0s, followed by the decimal point if necessary
    return s.TrimEnd('0').TrimEnd(point);
}

使用 System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator 代替 '.'? - Yoshi

2
有点像 hack 的,但这应该可以工作:
decimal a = 100.00M;
string strNumber = string.Format("{0}", a);
Console.WriteLine(strNumber.Contains('.') ? strNumber.TrimEnd('0').TrimEnd('.') : strNumber);

啊!如果a = 100.000呢?或者a = 0呢? - Gabe
@Gabe 正在修复的过程中。 - Davy8
@kerk现在应该已经修复了。如果您发现任何反例,请告诉我更新后的答案。 - Davy8
除非更新后的答案仍然不令人满意,否则您介意撤销一次负评吗? - Davy8

2

1
String.Format("{0:0.##}", 123.0); // "123"

应该是... String.Format("{0:0.0##}", 123.456789m)。谢谢。 - John K.

1

我相信你想要做的是:

var s = String.Format("{0:#####.###}");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接