最佳方法显示小数,不带尾随零

132

在C#中,是否有一种显示格式化程序,可以将小数以这些字符串表示方式输出,而不进行任何舍入?

// decimal -> string

20 -> 20
20.00 -> 20
20.5 -> 20.5
20.5000 -> 20.5
20.125 -> 20.125
20.12500 -> 20.125
0.000 -> 0

使用{0.#}将进行四舍五入,而在网格中使用一些Trim类型的函数将无法处理绑定到数字列的内容。

14个回答

175

你是否有需要显示的小数位数的最大值?(你的示例最多只有5个)

如果有的话,我认为使用"0.#####"格式化可以达到你想要的效果。

    static void Main(string[] args)
    {
        var dList = new decimal[] { 20, 20.00m, 20.5m, 20.5000m, 20.125m, 20.12500m, 0.000m };

        foreach (var d in dList)
            Console.WriteLine(d.ToString("0.#####"));
    }

5
你可以随时往格式里加入任意数量的 # 符号。*此非科学用语。 - Anthony Pegram
3
顺便提一句,你不需要在前面加上 # 号。"0.#####" 的效果是完全相同的。而且无论哪种方式,这都会从零四舍五入(仅供参考)。 - TrueWill
15
实际上,这确实会有所不同。如果d==0.1m,则“0.#”将呈现为“0.1”,而“#.#”将呈现为“.1”,没有前导0。两者都不对也不错,只是取决于你想要什么。 - AaronLS

45

我刚学会如何正确使用G格式说明符。请参阅MSDN文档。文档稍微往下有一个注释,说明当没有指定精度时,小数类型的尾随零将被保留。为什么他们要这样做我不知道,但是指定最大数字作为精度应该可以解决这个问题。因此,对于格式化十进制数,G29是最好的选择。

decimal test = 20.5000m;
test.ToString("G"); // outputs 20.5000 like the documentation says it should
test.ToString("G29"); // outputs 20.5 which is exactly what we want

25
这会导致0.00001显示为1E-05。 - sehe

20

这个字符串格式可以让你的一天变得更美好: "0.#############################"。但要记住,小数最多只能有29位有效数字。

例如:

? (1000000.00000000000050000000000m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.00000000000050000000001m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.0000000000005000000001m).ToString("0.#############################")
-> 1000000.0000000000005000000001

? (9223372036854775807.0000000001m).ToString("0.#############################")
-> 9223372036854775807

? (9223372036854775807.000000001m).ToString("0.#############################")
-> 9223372036854775807.000000001

4
这是该问题的最通用答案。不确定为什么这不是十进制中默认的“G”格式。尾部的零不增加任何信息。Microsoft文档对于十进制有一个奇怪的注意事项:https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#GFormatString但是,如果数字是Decimal类型并且省略了精度说明符,则始终使用定点表示法并保留尾随零。 - Eric Roller

11

这是我在上面看到的另一种变体。 在我的情况下,我需要保留小数点右侧所有有效数字,即删除最显著数字后的所有零。 只是想分享一下。 虽然我不能保证其效率,但当尝试实现美学时,你已经几乎注定要低效。

public static string ToTrimmedString(this decimal target)
{
    string strValue = target.ToString(); //Get the stock string

    //If there is a decimal point present
    if (strValue.Contains("."))
    {
        //Remove all trailing zeros
        strValue = strValue.TrimEnd('0');

        //If all we are left with is a decimal point
        if (strValue.EndsWith(".")) //then remove it
            strValue = strValue.TrimEnd('.');
    }

    return strValue;
}

就这些了,我只是想提出我的观点。


6

另一种解决方案,基于 dyslexicanaboko 的答案,但与当前文化无关:

public static string ToTrimmedString(this decimal num)
{
    string str = num.ToString();
    string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    if (str.Contains(decimalSeparator))
    {
        str = str.TrimEnd('0');
        if(str.EndsWith(decimalSeparator))
        {
            str = str.RemoveFromEnd(1);
        }
    }
    return str;
}

public static string RemoveFromEnd(this string str, int characterCount)
{
    return str.Remove(str.Length - characterCount, characterCount);
}

太好了。除了SqlDecimal之外,它是CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator,尽管区域设置不同。 - user2091150

3

如果您希望接受科学计数法,可以使用G0格式字符串,如文档所述:

如果将数字表示为科学计数法会产生的指数大于-5且小于精度说明符,则使用定点表示法;否则,使用科学计数法。

您可以将此格式字符串用作.ToString()方法的参数,或者在插值字符串中指定它。两者都在下面显示。

decimal hasTrailingZeros = 20.12500m;
Console.WriteLine(hasTrailingZeros.ToString("G0")); // outputs 20.125
Console.WriteLine($"{hasTrailingZeros:G0}"); // outputs 20.125

decimal fourDecimalPlaces = 0.0001m;
Console.WriteLine(fourDecimalPlaces.ToString("G0")); // outputs 0.0001
Console.WriteLine($"{fourDecimalPlaces:G0}"); // outputs 0.0001

decimal fiveDecimalPlaces = 0.00001m;
Console.WriteLine(fiveDecimalPlaces.ToString("G0")); // outputs 1E-05
Console.WriteLine($"{fiveDecimalPlaces:G0}"); // outputs 1E-05

2

扩展方法:

public static class Extensions
{
    public static string TrimDouble(this string temp)
    {
        var value = temp.IndexOf('.') == -1 ? temp : temp.TrimEnd('.', '0');
        return value == string.Empty ? "0" : value;
    }
}

示例代码:

double[] dvalues = {20, 20.00, 20.5, 20.5000, 20.125, 20.125000, 0.000};
foreach (var value in dvalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.ToString().TrimDouble()));

Console.WriteLine("==================");

string[] svalues = {"20", "20.00", "20.5", "20.5000", "20.125", "20.125000", "0.000"};
foreach (var value in svalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.TrimDouble()));

输出:

20 --> 20
20 --> 20
20,5 --> 20,5
20,5 --> 20,5
20,125 --> 20,125
20,125 --> 20,125
0 --> 0
==================
20 --> 20
20.00 --> 2
20.5 --> 20.5
20.5000 --> 20.5
20.125 --> 20.125
20.125000 --> 20.125
0.000 --> 0

1
"20.00 --> 2" 我认为这不是好的行为。要修复它,请调用 TrimEnd 两次:TrimEnd('0'); TrimEnd(','); - Vadym
4
请勿使用上面写的代码。@VadymK是正确的,它的行为有缺陷。如果没有小数点,则会修剪在小数点之前的尾随零。 - Sevin7

2
我认为这不可能从一开始就实现,但像这样的简单方法应该可以做到。
public static string TrimDecimal(decimal value)
{
    string result = value.ToString(System.Globalization.CultureInfo.InvariantCulture);
    if (result.IndexOf('.') == -1)
        return result;

    return result.TrimEnd('0', '.');
}

2

这在开箱即用情况下非常容易实现:

Decimal YourValue; //just as example   
String YourString = YourValue.ToString().TrimEnd('0','.');

这段代码可以从你的 Decimal 中删除所有尾随的零。

唯一需要做的是在 decimal 变量后添加 .ToString().TrimEnd('0','.');,就可以将 Decimal 转换为没有尾随零的 String,就像上面的例子一样。

在某些地区,应该使用 .ToString().TrimEnd('0',',');(他们使用逗号而不是点号),但您也可以添加点和逗号作为参数以确保正确。

(您也可以将两者都添加为参数)


gr8。现在你的代码只剩下“0.0”了,会产生一个空字符串。 - jgauffin
3
我建议使用.ToString().TrimEnd('0').TrimEnd('.'),而不是'.'最好使用CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator,这样可以适用于不同的文化背景。 - Ε Г И І И О
@Mervin,请修改你的回答以反映ΕГИІИО的评论。你的代码会将50.0m格式化为5,这显然是一个错误。 - Ethan Reesor
踩票。这将把20变成2 :/ - nawfal

1
decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');

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