显示十进制而不尾随零的最佳方法


107

是否有一个显示格式化程序,可以在不进行任何舍入的情况下将小数作为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类型函数将不适用于网格中的绑定数字列。

Answers:


147

您是否需要显示最大小数位数?(您的示例最多为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.#####"));
    }

4
而且,您总是可以在格式中抛出数量过多的#个符号。*不科学
安东尼Pegram

3
+1-顺便说一句,您不需要开头的#。“ 0。#####”的工作原理相同。无论哪种方式,它的确舍入为零(仅为FYI)。
TrueWill

14
@TrueWill实际上,确实有所作为。d == 0.1m,那么“ 0.#”将呈现“ 0.1”,而“#。#”将呈现“ .1”,且不以前导0开头。无论是对还是错,都取决于您想要的内容。
AaronLS

4
我需要始终显示一位小数,因此我使用了格式字符串"0.0#"
锤子代码,2013年

1
请参阅下面的Erwin Mayer答案。
shlgug

32

我刚刚学习了如何正确使用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

21
这将导致虽然显示为1E-05 0.00001
sehe

17

此字符串格式应使您的生活变得美好:“ 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文档对十进制有一个怪异的警告: docs.microsoft.com/en-us/dotnet/standard/base-types/… 但是,如果数字为Decimal,并且省略了精度说明符,则始终使用定点表示法和尾随零被保留。
艾瑞克·罗勒

10

这是我上面看到的另一种变化。就我而言,我需要保留小数点右边的所有有效数字,这意味着将所有零都放在最高有效数字之后。只是认为分享会很好。虽然我不能保证这样做的效率,但是当尝试实现美学效果时,您已经非常无效率了。

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;
}

仅此而已,我只想投入两分钱。


3
这很容易是最好的解决方案,也不会炸为“ 0.0”。我添加了一个默认标志,使整数有选择地显示为“ 1.0”,这刚好使我的所有小数点都符合要求。无法理解为什么这不是最佳答案,很多。
史蒂夫·希伯特

2
如果有人已经向您传递了字符串,这特别好。您可以将其更改为ToTrimmedString(此字符串strValue)并删除第一行。
PRMan

那是个很好的观点。我想当我写这篇文章的时候,我正在处理已经是十进制数的值,所以我想涵盖整个内容。相反,您可以将该方法的主体放在另一个接受字符串的重载方法中。
dyslexicanaboko

当您可以调用ToTrimmedString()时,这是一个很好的解决方案,但是在许多情况下,您只能使用格式字符串。
Mike Marynowski

1
尽管十进制分隔符必须特定于文化,但我认为这是一个很好的解决方案。一个小问题,为什么不干脆strValue.TrimEnd('0').TrimEnd('.'),而不是EndsWith检查?
nawfal

5

另一个解决方案基于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

4

扩展方式:

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(',');
Vadim 2014年

2
不要使用上面写的代码。@VadymK是正确的,它的行为有缺陷。如果没有周期,它将修剪该周期之前的尾随零。
Sevin7年

2
关于stackoverflow的答案不适用于复制粘贴。它们被用作学习的来源。此示例代码教您如何IndexOf在字符串中查找字符。调整示例以解决此问题非常容易,没有小数。
jgauffin

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','.');

这将删除十进制中的所有尾随零。

您唯一需要做的就是将其添加.ToString().TrimEnd('0','.');到一个十进制变量中,以将a Decimal转换为String不带尾随零的a,如上例所示。

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

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


您可能没有意识到这一点,但是在处理params参数时,不必显式构造数组。因此,TrimEnd("0".ToCharArray())您无需编写冗长的代码TrimEnd('0')(请注意:传递单值char而不是char[])。
丹涛2010年

@丹涛:谢谢,我忘了。自从我使用C#已经有一段时间了。虽然两个版本都可以,但是我已经编辑了我的帖子。
Mervin 2010年

@Mervin:您需要传递a char,而不是a string(因此:单引号,而不是双引号)。我为您修复了它-希望您不介意。
丹涛2010年

1
您的解决方案将产生类似“ 2”的输出。当它只有零时。
jgauffin 2010年

2
然后,我建议调用.ToString()。TrimEnd('0')。TrimEnd('。')。也代替“。” 最好具有CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator,以便跨文化使用。
ΕГИІИО

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

0

我最终得到了以下代码:

    public static string DropTrailingZeros(string test)
    {
        if (test.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.TrimEnd('0');
        }

        if (test.EndsWith(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.Substring(0,
                test.Length - CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator.Length);
        }

        return test;
    }

0

我最终得到了这个变体:

public static string Decimal2StringCompact(decimal value, int maxDigits)
    {
        if (maxDigits < 0) maxDigits = 0;
        else if (maxDigits > 28) maxDigits = 28;
        return Math.Round(value, maxDigits, MidpointRounding.ToEven).ToString("0.############################", CultureInfo.InvariantCulture);
    }

优点:

您可以指定要在运行时显示的点之后的最大有效位数;

您可以显式指定舍入方法;

您可以显式控制文化。


0

您可以创建扩展方法

public static class ExtensionMethod {
  public static decimal simplify_decimal(this decimal value) => decimal.Parse($"{this:0.############}");
}

0

我为自己制定了以下扩展方法以适合我的项目之一,但也许对其他人会有所帮助。

using System.Numerics;
using System.Text.RegularExpressions;
internal static class ExtensionMethod
{
    internal static string TrimDecimal(this BigInteger obj) => obj.ToString().TrimDecimal();
    internal static string TrimDecimal(this decimal obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this double obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this float obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this string obj)
    {
        if (string.IsNullOrWhiteSpace(obj) || !Regex.IsMatch(obj, @"^(\d+([.]\d*)?|[.]\d*)$")) return string.Empty;
        Regex regex = new Regex("^[0]*(?<pre>([0-9]+)?)(?<post>([.][0-9]*)?)$");
        MatchEvaluator matchEvaluator = m => string.Concat(m.Groups["pre"].Length > 0 ? m.Groups["pre"].Value : "0", m.Groups["post"].Value.TrimEnd(new[] { '.', '0' }));
        return regex.Replace(obj, matchEvaluator);
    }
}

尽管这将需要引用System.Numerics

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.