Cara terbaik untuk menampilkan desimal tanpa nol

107

Apakah ada pemformat tampilan yang akan mengeluarkan desimal sebagai representasi string ini di c # tanpa melakukan pembulatan apa pun?

// 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. #} akan membulatkan, dan menggunakan beberapa fungsi tipe Trim tidak akan bekerja dengan kolom numerik terikat dalam kisi.

JC.
sumber

Jawaban:

147

Apakah Anda memiliki jumlah tempat desimal maksimum yang perlu Anda tampilkan? (Contoh Anda memiliki maksimal 5).

Jika demikian, menurut saya pemformatan dengan "0. #####" akan melakukan apa yang Anda inginkan.

    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.#####"));
    }
Toby
sumber
4
Dan Anda selalu dapat melempar simbol # dalam jumlah yang terlalu tinggi * ke format. * tidak ilmiah
Anthony Pegram
3
+1 - kebetulan, Anda tidak perlu memimpin #. "0. #####" bekerja secara identik. Dan bagaimanapun, ini membulatkan jauh dari nol (hanya FYI).
TrueWill
14
@TrueWill Sebenarnya itu membuat perbedaan. d == 0.1m lalu "0. #" menjadikan "0.1" dan "#. #" render ".1" tanpa awalan 0. Tidak ada yang salah atau benar, hanya tergantung pada apa yang Anda inginkan.
AaronLS
4
Saya perlu menampilkan satu tempat desimal setiap saat, jadi saya menggunakan format string "0.0#".
Kode dengan Hammer
1
Lihat jawaban Erwin Mayer di bawah ini.
shlgug
32

Saya baru saja mempelajari cara menggunakan Gpenentu format dengan benar . Lihat Dokumentasi MSDN . Ada catatan sedikit di bawah yang menyatakan bahwa nol di belakang akan dipertahankan untuk tipe desimal jika tidak ada presisi yang ditentukan. Mengapa mereka melakukan ini saya tidak tahu, tetapi menentukan jumlah digit maksimum untuk ketepatan kami harus memperbaiki masalah itu. Jadi untuk memformat desimal, G29adalah yang terbaik.

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
Schmalls
sumber
21
Ini akan menyebabkan 0,00001 ditampilkan sebagai 1E-05 meskipun
lihat
17

Format string ini akan membuat hari Anda menjadi: "0. ############################". Perlu diingat bahwa desimal dapat memiliki paling banyak 29 digit signifikan.

Contoh:

? (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
Erwin Mayer
sumber
4
Ini adalah jawaban paling umum untuk masalah tersebut. Tidak yakin mengapa ini bukan format "G" default untuk desimal. Angka nol di belakangnya tidak menambahkan informasi. Dokumentasi Microsoft memiliki peringatan aneh untuk desimal: docs.microsoft.com/en-us/dotnet/standard/base-types/… Namun, jika angkanya adalah Desimal dan penentu presisi dihilangkan, notasi titik tetap selalu digunakan dan nol tertinggal tetap dipertahankan.
Eric Roller
10

Ini adalah variasi lain dari apa yang saya lihat di atas. Dalam kasus saya, saya perlu mempertahankan semua digit signifikan di sebelah kanan koma desimal, yang berarti hilangkan semua angka nol setelah digit paling signifikan. Hanya berpikir akan menyenangkan untuk berbagi. Saya tidak dapat menjamin efisiensi ini, tetapi ketika mencoba mencapai estetika, Anda sudah terkutuk dengan inefisiensi.

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

Itu saja, hanya ingin memberikan dua sen saya.

dyslexicanaboko.dll
sumber
3
Ini adalah solusi terbaik yang mudah, juga tidak meledak untuk "0,0". Saya menambahkan bendera default untuk membuat bilangan bulat secara opsional ditampilkan sebagai "1.0", dan ini baru saja membuat semua desimal saya sesuai. Tidak dapat memahami mengapa ini bukan jawaban terbaik, + lot.
Steve Hibbert
2
Ini sangat bagus jika seseorang telah memberikan Anda string. Anda bisa mengubahnya menjadi ToTrimmedString (string strValue ini) dan menghapus baris pertama.
PRMan
Itu poin yang bagus. Saya pikir ketika saya menulis ini saya berurusan dengan nilai-nilai yang sudah desimal atau sesuatu jadi saya ingin mencakup semuanya. Sebagai gantinya, Anda dapat memiliki tubuh metode itu di dalam metode kelebihan beban lain yang menerima string.
dyslexicanaboko
Ini adalah solusi yang bagus ketika Anda dapat memanggil ToTrimmedString () tetapi ada banyak kasus di mana Anda dibatasi pada string format.
Mike Marynowski
1
Sementara pemisah desimal harus spesifik budaya, saya pikir ini adalah solusi yang baik. Sebuah pertanyaan kecil, mengapa tidak hanya strValue.TrimEnd('0').TrimEnd('.')bukan EndsWithcek?
nawfal
5

Solusi lain, berdasarkan jawaban dyslexicanaboko , tetapi tidak bergantung pada budaya saat ini:

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);
}
David Dostal
sumber
Bagus. Kecuali SqlDecimal itu adalah CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator meskipun pengaturan regional.
pengguna2091150
4

Metode ekstensi:

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

Kode contoh:

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()));

Keluaran:

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
jgauffin.dll
sumber
1
"20.00 -> 2" Saya pikir itu bukan perilaku yang baik. Untuk memperbaikinya panggil TrimEnd dua kali: TrimEnd ('0'); TrimEnd (',');
Vadim
2
JANGAN GUNAKAN kode yang tertulis di atas. @VadymK benar bahwa perilakunya cacat. Ini akan memangkas nol tertinggal yang SEBELUM titik jika tidak ada titik.
Sevin7
2
Jawaban di stackoverflow bukan untuk salin-tempel. Mereka digunakan sebagai sumber belajar . Kode sampel ini mengajarkan Anda untuk menggunakan IndexOfuntuk menemukan karakter dalam sebuah string. Cukup mudah untuk menyesuaikan contoh untuk menyelesaikan soal tanpa desimal.
jgauffin
2

Saya tidak berpikir itu mungkin out-of-the-box tetapi metode sederhana seperti ini harus melakukannya

public static string TrimDecimal(decimal value)
{
    string result = value.ToString(System.Globalization.CultureInfo.InvariantCulture);
    if (result.IndexOf('.') == -1)
        return result;

    return result.TrimEnd('0', '.');
}
Tim Skauge
sumber
2

Ini cukup mudah dilakukan di luar kotak:

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

yang akan menghapus semua nol di belakang Desimal Anda.

Satu-satunya hal yang perlu Anda lakukan adalah menambahkan .ToString().TrimEnd('0','.');variabel desimal untuk mengubah a Decimalmenjadi a Stringtanpa membuntuti nol, seperti pada contoh di atas.

Di beberapa wilayah, ini harus berupa .ToString().TrimEnd('0',',');(di mana mereka menggunakan koma, bukan titik, tetapi Anda juga dapat menambahkan titik dan koma sebagai parameter untuk memastikan).

(Anda juga dapat menambahkan keduanya sebagai parameter)

Mervin
sumber
Anda mungkin tidak menyadarinya, tetapi saat berhadapan dengan paramsargumen, Anda tidak harus membuat array secara eksplisit. Jadi alih-alih verbose TrimEnd("0".ToCharArray())Anda bisa menulis TrimEnd('0')(catatan: lulus tunggal charbukan a char[]).
Dan Tao
@ Dan Tao: Terima kasih, saya lupa itu. Sudah lama sejak saya menggunakan C #. Meskipun kedua versi berfungsi, saya telah mengedit posting saya.
Mervin
@Mervin: Anda harus meneruskan a char, bukan a string(jadi: tanda kutip tunggal, bukan tanda kutip ganda). Saya memperbaikinya untuk Anda - semoga Anda tidak keberatan.
Dan Tao
1
Solusi Anda akan menghasilkan keluaran seperti "2." ketika hanya mendapat nol.
jgauffin
2
Maka saya akan menyarankan untuk memanggil .ToString (). TrimEnd ('0'). TrimEnd ('.'). Juga bukan '.' lebih baik memiliki CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator sehingga berfungsi lintas budaya.
Ε Г И І И О
1
decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');
Jerry Liang
sumber
0

Saya berakhir dengan kode berikut:

    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;
    }
Arsen Zahray
sumber
0

Saya telah berakhir dengan varian ini:

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

Keuntungan:

Anda dapat menentukan jumlah maksimal digit signifikan setelah titik yang akan ditampilkan saat runtime;

Anda dapat secara eksplisit menentukan metode bulat;

Anda dapat mengontrol budaya secara eksplisit.

lilo0
sumber
0

Anda dapat membuat metode ekstensi

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

Saya membuat metode ekstensi di bawah ini untuk diri saya sendiri agar sesuai dengan salah satu proyek saya, tetapi mungkin itu akan bermanfaat bagi orang lain.

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

Padahal itu akan membutuhkan referensi System.Numerics.

Jeremy McCrorie
sumber