我有一些由集合返回的字段

2.4200
2.0044
2.0000

我想要这样的结果

2.42
2.0044
2

我试过用String。格式,但它返回2.0000,并将其设置为N0也会四舍五入其他值。


当前回答

尝试做更友好的解决方案DecimalToString (https://stackoverflow.com/a/34486763/3852139):

private static decimal Trim(this decimal value)
{
    var s = value.ToString(CultureInfo.InvariantCulture);
    return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
        ? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
        : value;
}

private static decimal? Trim(this decimal? value)
{
    return value.HasValue ? (decimal?) value.Value.Trim() : null;
}

private static void Main(string[] args)
{
    Console.WriteLine("=>{0}", 1.0000m.Trim());
    Console.WriteLine("=>{0}", 1.000000023000m.Trim());
    Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
    Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}

输出:

=>1
=>1.000000023
=>1.000000023
=>

其他回答

我使用这个代码来避免“G29”科学符号:

public static string DecimalToString(this decimal dec)
{
    string strdec = dec.ToString(CultureInfo.InvariantCulture);
    return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}

编辑:使用系统CultureInfo.NumberFormat.NumberDecimalSeparator:

public static string DecimalToString(this decimal dec)
{
    string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    string strdec = dec.ToString(CultureInfo.CurrentCulture);
    return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}

这个怎么样:

public static string TrimEnd(this decimal d)
    {
        string str = d.ToString();
        if (str.IndexOf(".") > 0)
        {
            str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "0+?$", " ");
            str = System.Text.RegularExpressions.Regex.Replace(str.Trim(), "[.]$", " ");
        }
        return str;
    }

尝试做更友好的解决方案DecimalToString (https://stackoverflow.com/a/34486763/3852139):

private static decimal Trim(this decimal value)
{
    var s = value.ToString(CultureInfo.InvariantCulture);
    return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
        ? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
        : value;
}

private static decimal? Trim(this decimal? value)
{
    return value.HasValue ? (decimal?) value.Value.Trim() : null;
}

private static void Main(string[] args)
{
    Console.WriteLine("=>{0}", 1.0000m.Trim());
    Console.WriteLine("=>{0}", 1.000000023000m.Trim());
    Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
    Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}

输出:

=>1
=>1.000000023
=>1.000000023
=>

一个非常低级的方法,但我相信这将是最高效的方法,只使用快速整数计算(没有缓慢的字符串解析和区域性敏感的方法):

public static decimal Normalize(this decimal d)
{
    int[] bits = decimal.GetBits(d);

    int sign = bits[3] & (1 << 31);
    int exp = (bits[3] >> 16) & 0x1f;

    uint a = (uint)bits[2]; // Top bits
    uint b = (uint)bits[1]; // Middle bits
    uint c = (uint)bits[0]; // Bottom bits

    while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
    {
        uint r;
        a = DivideBy10((uint)0, a, out r);
        b = DivideBy10(r, b, out r);
        c = DivideBy10(r, c, out r);
        exp--;
    }

    bits[0] = (int)c;
    bits[1] = (int)b;
    bits[2] = (int)a;
    bits[3] = (exp << 16) | sign;
    return new decimal(bits);
}

private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
    ulong total = highBits;
    total <<= 32;
    total = total | (ulong)lowBits;

    remainder = (uint)(total % 10L);
    return (uint)(total / 10L);
}

如果输入是一个字符串,它不是这么简单吗?你可以使用其中一个:

string.Format("{0:G29}", decimal.Parse("2.0044"))

decimal.Parse("2.0044").ToString("G29")

2.0m.ToString("G29")

这应该适用于所有输入。

我必须显式地将精度说明符设置为29,因为文档清楚地声明:

但是,如果数字是Decimal且省略了精度说明符,则始终使用定点表示法并保留后面的零

Konrad在评论中指出:

注意像0.000001这样的值。G29格式将以最短的方式表示它们,因此它将切换到指数符号。字符串。Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))将给出"1E-08"作为结果。