Sıfırları takip etmeden ondalık sayıyı görüntülemenin en iyi yolu


108

Herhangi bir yuvarlama yapmadan c # 'da bu dize temsilleri olarak ondalık sayılar çıkaracak bir görüntü biçimlendiricisi var mı?

// 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. #} yuvarlanır ve bazı Kırpma türü işlevlerinin kullanılması, bir ızgarada bağlı bir sayısal sütunla çalışmaz.

Yanıtlar:


147

Görüntülemeniz gereken maksimum sayıda ondalık hane var mı? (Örneklerinizde maksimum 5).

Öyleyse, "0. #####" ile biçimlendirmenin istediğinizi yapacağını düşünürdüm.

    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
Ve biçime her zaman aşırı * sayıda # simge atabilirsiniz. * bilimsel değil
Anthony Pegram

3
+1 - bu arada, baştaki numaraya ihtiyacınız yok. "0. #####" aynı şekilde çalışır. Her iki durumda da, bu sıfırdan uzaklaşır (sadece FYI).
TrueWill

14
@TrueWill Aslında bir fark yaratıyor. d == 0.1m sonra "0. #", "0.1" i oluşturur ve "#. #", baştaki 0 ​​olmadan ".1" oluşturur. Ne yanlış ne de doğru, sadece ne istediğinize bağlıdır.
AaronLS

4
Her zaman bir ondalık basamak göstermem gerekiyordu, bu yüzden biçim dizesini kullandım "0.0#".
Çekiçli Kodlar

1
Aşağıdaki Erwin Mayer'in cevabına bakın.
shlgug

32

GBiçim belirticisinin nasıl doğru bir şekilde kullanılacağını öğrendim . MSDN Belgelerine bakın . Kesinlik belirtilmediğinde ondalık türler için sondaki sıfırların korunacağını belirten küçük bir not vardır. Bunu neden yaptılar bilmiyorum ama kesinliğimiz için maksimum basamak sayısını belirtmek bu sorunu çözmelidir. Dolayısıyla, ondalık sayıları biçimlendirmek G29için en iyi seçim budur.

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
Bu, 0.00001'in 1E-05 olarak görüntülenmesine yol açacak
sehe

17

Bu dize biçimi gününüzü: "0. #############################" yapmalıdır. Yine de ondalık sayıların en fazla 29 anlamlı basamağa sahip olabileceğini unutmayın.

Örnekler:

? (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
Sorunun en genel cevabı budur. Bunun neden ondalık sayı için varsayılan "G" biçimi olmadığından emin değilim. Sondaki sıfırlar bilgi eklemez. Microsoft belgelerinde ondalık sayı için garip bir uyarı vardır: docs.microsoft.com/en-us/dotnet/standard/base-types/… Bununla birlikte, sayı bir Ondalık ise ve kesinlik belirticisi atlanmışsa, her zaman sabit noktalı gösterim kullanılır ve sondaki sıfırlar korunur.
Eric Roller

10

Bu, yukarıda gördüğüm şeyin bir başka varyasyonudur. Benim durumumda, ondalık noktanın sağındaki tüm önemli basamakları korumam gerekiyor, yani en önemli basamaktan sonra tüm sıfırları bırak. Paylaşmanın güzel olacağını düşündüm. Yine de bunun verimliliğine kefil olamam, ancak estetiğe ulaşmaya çalıştığınızda, zaten verimsizliklere büyük ölçüde lanetlendiniz.

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

Hepsi bu, sadece iki sentimi atmak istedim.


3
Bu kolayca en iyi çözümdür, "0.0" için de patlamaz. Tam sayıları isteğe bağlı olarak "1.0" olarak göstermek için varsayılan bir bayrak ekledim ve bu tüm ondalık sayılarımın satıra düşmesine neden oldu. Bunun neden en iyi cevap olmadığını anlayamıyorum + çok.
Steve Hibbert

2
Bu, özellikle birisi size zaten bir dizi geçirdiyse iyidir. Bunu ToTrimmedString (bu strValue dize) olarak değiştirebilir ve ilk satırı kaldırabilirsiniz.
PRMan

İyi bir noktaya değindin. Sanırım bunu yazarken zaten ondalık olan değerlerle veya başka bir şeyle uğraşıyordum, bu yüzden her şeyi kapsamak istedim. Bunun yerine, bu yöntemin gövdesini, bunun yerine bir dizeyi kabul eden başka bir aşırı yüklenmiş yöntemin içinde bulundurabilirsiniz.
dyslexicanaboko

ToTrimmedString () 'i çağırabildiğinizde bu iyi bir çözümdür, ancak bir biçim dizesiyle sınırlı olduğunuz birçok durum vardır.
Mike Marynowski

1
Ondalık ayırıcının kültüre özgü olması gerekirken, bunun iyi bir çözüm olduğunu düşünüyorum. Küçük bir soru, neden sadece çek strValue.TrimEnd('0').TrimEnd('.')yerine değil EndsWith?
nawfal

5

Dislexicanaboko'nun cevabına dayanan , ancak mevcut kültürden bağımsız başka bir çözüm :

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

Harika. SqlDecimal dışında, bölgesel ayarlara rağmen CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator.
user2091150

4

Uzatma yöntemi:

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

Örnek kod:

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

Çıktı:

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" Bunun iyi bir davranış olmadığını düşünüyorum. Düzeltmek için TrimEnd'i iki kez çağırın: TrimEnd ('0'); TrimEnd (',');
Vadim

2
Yukarıda yazılı kodu KULLANMAYIN. @VadymK, davranışının kusurlu olduğu konusunda doğru. Nokta yoksa, noktadan ÖNCE olan sondaki sıfırları kırpacaktır.
Sevin7

2
Stackoverflow'daki cevaplar kopyala-yapıştır için değildir. Bir öğrenme kaynağı olarak kullanılırlar . Bu örnek kod size IndexOfbir dizedeki karakterleri bulmayı öğretir . Ondalık sayı olmadan sorunu çözmek için örneği ayarlamak oldukça kolaydır.
jgauffin

2

Kutudan çıkar çıkmaz mümkün olduğunu sanmıyorum ama bunun gibi basit bir yöntem bunu yapmalı

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

Kutudan çıkar çıkmaz yapmak oldukça kolaydır:

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

Bu, Decimal'inizdeki tüm sıfırları kaldıracaktır.

Yapmanız gereken tek şey eklenti olan .ToString().TrimEnd('0','.');bir ondalık değişkene bir dönüştürmek için Decimalbir içine Stringyukarıdaki örnekte olduğu gibi, sondaki sıfırlar olmadan.

Bazı bölgelerde bir olmalıdır .ToString().TrimEnd('0',',');(burada nokta yerine virgül kullanırlar, ancak emin olmak için parametre olarak nokta ve virgül de ekleyebilirsiniz).

(her ikisini de parametre olarak ekleyebilirsiniz)


Bunu fark etmeyebilirsiniz, ancak bir paramsargümanla uğraşırken , açıkça bir dizi oluşturmanız gerekmez. Yani ayrıntılı yerine TrimEnd("0".ToCharArray())sadece yazabilirsiniz TrimEnd('0')(not: chara yerine single geçti char[]).
Dan Tao

@Dan Tao: Teşekkürler, bunu unuttum. C # kullanmayalı uzun zaman oldu. Her iki sürüm de çalışmasına rağmen, yazımı düzenledim.
Mervin

@Mervin: a geçmelisiniz, a chardeğil string(yani: tek tırnak, çift tırnak değil). Senin için düzelttim - umarım aldırmazsın.
Dan Tao

1
Çözümünüz "2" gibi çıktı üretecektir. sadece sıfır olduğunda.
jgauffin

2
O zaman .ToString (). TrimEnd ('0'). TrimEnd ('.') 'İ çağırmanızı öneririm. Ayrıca "." Yerine Kültürler arasında çalışması için CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator'a sahip olmak daha iyidir.
Ε Г И І И О

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

0

Aşağıdaki kodu buldum:

    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

Bu değişkeni elde ettim:

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

Avantajlar:

çalışma zamanında görüntülenecek noktadan sonra maksimum anlamlı basamak sayısını belirtebilirsiniz;

açıkça bir yuvarlak yöntem belirtebilirsiniz;

bir kültürü açıkça kontrol edebilirsiniz.


0

Uzatma yöntemi oluşturabilirsiniz

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

0

Projelerimden birine uyması için aşağıdaki uzatma yöntemlerini kendim için yaptım ama belki başkası için faydalı olur.

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

Bir referans gerektirecek olsa da System.Numerics.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.