วิธีที่ดีที่สุดในการแสดงทศนิยมโดยไม่มีศูนย์ต่อท้าย


109

มีตัวจัดรูปแบบการแสดงที่จะแสดงทศนิยมเป็นตัวแทนสตริงเหล่านี้ใน 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 บางอย่างจะไม่ทำงานกับคอลัมน์ตัวเลขที่ถูกผูกไว้ในตาราง

คำตอบ:


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
และคุณสามารถโยนสัญลักษณ์ # จำนวนมากเกินไปในรูปแบบได้เสมอ * ไม่เป็นวิทยาศาสตร์
Anthony Pegram

3
+1 - โดยบังเอิญคุณไม่จำเป็นต้องมี # ชั้นนำ "0. #####" ทำงานเหมือนกัน และไม่ว่าจะด้วยวิธีใดสิ่งนี้จะปัดเศษจากศูนย์ (แค่ FYI)
TrueWill

14
@TrueWill จริงๆแล้วมันสร้างความแตกต่าง d == 0.1m จากนั้น "0. #" แสดงผล "0.1" และ "#. #" renders ".1" โดยไม่มี 0 นำหน้าไม่ว่าจะผิดหรือถูกเพียงขึ้นอยู่กับสิ่งที่คุณต้องการ
AaronLS

4
"0.0#"ฉันต้องการที่จะแสดงเป็นทศนิยมหนึ่งตำแหน่งตลอดเวลาดังนั้นผมจึงใช้สตริงรูปแบบ
รหัสกับ Hammer

1
ดูคำตอบของ Erwin Mayer ด้านล่าง
shlgug

33

ฉันเพิ่งเรียนรู้วิธีใช้ตัว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
สิ่งนี้จะนำไปสู่ ​​0.00001 ที่แสดงเป็น 1E-05 แม้ว่า
ดู

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/… อย่างไรก็ตามหากตัวเลขเป็นทศนิยมและตัวระบุความแม่นยำถูกละไว้จะใช้สัญกรณ์จุดคงที่เสมอ และศูนย์ต่อท้ายจะถูกเก็บรักษาไว้
Eric Roller

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" ได้และสิ่งนี้ทำให้ทศนิยมทั้งหมดของฉันอยู่ในแนวเดียวกัน ไม่เข้าใจว่าทำไมนี่ไม่ใช่คำตอบที่ดีที่สุด + มากมาย
Steve Hibbert

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

3

วิธีการขยาย:

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

3
อย่าใช้รหัสที่เขียนไว้ข้างต้น @ 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 .ToString().TrimEnd('0',',');(โดยที่ใช้เครื่องหมายจุลภาคแทนจุด แต่คุณยังสามารถเพิ่มจุดและลูกน้ำเป็นพารามิเตอร์เพื่อให้แน่ใจได้)

(คุณสามารถเพิ่มทั้งสองอย่างเป็นพารามิเตอร์ได้)


คุณอาจไม่รู้เรื่องนี้ แต่เมื่อต้องจัดการกับparamsอาร์กิวเมนต์คุณไม่จำเป็นต้องสร้างอาร์เรย์อย่างชัดเจน ดังนั้นแทนที่จะเป็น verbose TrimEnd("0".ToCharArray())คุณสามารถเขียนได้TrimEnd('0')(หมายเหตุ: ส่งผ่าน single charแทน a char[])
ด่านเทา

@ Dan Tao: ขอบคุณฉันลืมไปแล้ว เป็นเวลานานแล้วที่ฉันใช้ C # แม้ว่าทั้งสองเวอร์ชันจะใช้ได้ แต่ฉันได้แก้ไขโพสต์แล้ว
Mervin

@ เมอวิน: คุณต้องผ่าน a charไม่ใช่string(ดังนั้น: คำพูดเดี่ยวไม่ใช่คำพูดคู่) ฉันแก้ไขให้คุณ - หวังว่าคุณจะไม่รังเกียจ
ด่านเทา

1
โซลูชันของคุณจะให้ผลลัพธ์เช่น "2. " เมื่อมีเพียงศูนย์
jgauffin

2
จากนั้นฉันจะแนะนำให้โทร. ToString (). TrimEnd ('0'). TrimEnd ('.') แทน "." ด้วย จะดีกว่าที่จะมี CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator เพื่อให้ทำงานข้ามวัฒนธรรม
ΕГИІИО


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แม้ว่ามันจะต้องมีการอ้างอิงถึง


0

คุณสามารถใช้G0สตริงรูปแบบได้หากคุณยินดีที่จะยอมรับสัญกรณ์ทางวิทยาศาสตร์ตามเอกสารประกอบ :

ใช้สัญกรณ์จุดคงที่หากเลขชี้กำลังที่เป็นผลมาจากการแสดงจำนวนในสัญกรณ์วิทยาศาสตร์มากกว่า -5 และน้อยกว่าตัวระบุความแม่นยำ มิฉะนั้นจะใช้สัญกรณ์ทางวิทยาศาสตร์

คุณสามารถใช้สตริงรูปแบบนี้เป็นพารามิเตอร์สำหรับ.ToString()เมธอดหรือโดยระบุเป็นไฟล์สตริงภายใน ทั้งสองแสดงด้านล่าง

decimal input = 20.12500m;
Console.WriteLine(input.ToString("G0")); // outputs 20.125
Console.WriteLine($"{input: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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.