การใช้รูปแบบสตริงเพื่อแสดงทศนิยมได้ถึง 2 ตำแหน่งหรือจำนวนเต็มอย่างง่าย


291

ฉันมีฟิลด์ราคาที่จะแสดงซึ่งบางครั้งอาจเป็น 100 หรือ 100.99 หรือ 100.9 สิ่งที่ฉันต้องการคือการแสดงราคาเป็นทศนิยม 2 ตำแหน่งก็ต่อเมื่อมีการป้อนทศนิยมสำหรับราคานั้นเช่นถ้าเป็น 100 มันควรเท่านั้น แสดง 100 ไม่ใช่ 100.00 และถ้าราคาเท่ากับ 100.2 ก็ควรแสดง 100.20 เหมือนกันสำหรับ 100.22 ควรเหมือนกัน ฉัน googled และเจอตัวอย่างบางอย่าง แต่พวกเขาไม่ตรงกับสิ่งที่ฉันต้องการ:

// just two decimal places
String.Format("{0:0.00}", 123.4567);      // "123.46"
String.Format("{0:0.00}", 123.4);         // "123.40"
String.Format("{0:0.00}", 123.0);         // "123.00"


1
RE: "สิ่งที่ฉันต้องการคือการแสดงราคาในทศนิยม 2 ตำแหน่งเฉพาะเมื่อมีการป้อนทศนิยมสำหรับราคานั้น" - ดังนั้นหากผู้ใช้พิมพ์ "100.00" คุณต้องการแสดง "100.00" แต่ถ้าพวกเขาพิมพ์ "100" คุณต้องการแสดง "100" เท่านั้น - ประเภทตัวเลขเพียงติดตามค่าของตัวเลข - ไม่ใช่ตัวเลขที่ไม่มีนัยสำคัญที่ป้อนโดยผู้ใช้และที่ไม่ใช่ - สำหรับการที่คุณจะต้องใช้สตริง
— BrainSlugs83

2
@ BinaryWorrier ฉันคิดว่าคำถามนี้อาจซ้ำกัน แต่มีคำตอบที่ดีกว่าและสมบูรณ์กว่ามาก IMO อีกอันหนึ่งควรทำเครื่องหมายว่าซ้ำกับอันนี้
— Ryan Gates

1
เพียงเพิ่ม. แทนที่ (". 00", "")
— Dave Sumter

คำตอบ:


156

วิธีที่ไม่เหมาะสมจะเป็น:

var my = DoFormat(123.0);

ด้วยDoFormatการเป็นสิ่งที่ชอบ:

public static string DoFormat( double myNumber )
{
    var s = string.Format("{0:0.00}", myNumber);

    if ( s.EndsWith("00") )
    {
        return ((int)myNumber).ToString();
    }
    else
    {
        return s;
    }
}

ไม่สง่า แต่ทำงานให้ฉันในสถานการณ์ที่คล้ายกันในบางโครงการ


6
นี่ไม่ใช่คำถามที่ถาม - แต่เป็นจริง - ทำไมไม่ใช้เฉพาะสตริงรูปแบบ ("{0: 0.00}") แทนที่ (". 00", "")?
— BrainSlugs83

18
@ BrainSlugs83: ขึ้นอยู่กับหัวข้อปัจจุบันของตัวคั่นทศนิยมอาจจะไม่CurrentCulture .ยกเว้นว่าCultureInfo.InvariantCultureใช้กับstring.Formatคุณจะต้องตรวจสอบค่าของCultureInfo.NumberFormat.NumberDecimalSeparatorและนั่นจะเป็น PITA จริง :)
— Groo

@Uwe Keim ถ้าฉันมี60000int และฉันอยากให้มันเป็น60.000อย่างไร
— Prashant Pimpale

คำตอบนี้เป็นกรณีของ "การสร้างใหม่ล้อสี่เหลี่ยม" ไม่คำนึงถึงวัฒนธรรมการบัญชีหรือข้อเท็จจริงที่ว่าสิ่งนี้ได้รับการจัดการโดย. NET
— bytedev

523

ขออภัยที่เปิดใช้งานคำถามนี้อีกครั้ง แต่ฉันไม่พบคำตอบที่ถูกต้องที่นี่

ในการจัดรูปแบบตัวเลขคุณสามารถใช้0เป็นสถานที่บังคับและ#เป็นสถานที่เสริม

ดังนั้น:

// just two decimal places
String.Format("{0:0.##}", 123.4567);      // "123.46"
String.Format("{0:0.##}", 123.4);         // "123.4"
String.Format("{0:0.##}", 123.0);         // "123"

นอกจากนี้คุณยังสามารถรวมกับ0#

String.Format("{0:0.0#}", 123.4567)       // "123.46"
String.Format("{0:0.0#}", 123.4)          // "123.4"
String.Format("{0:0.0#}", 123.0)          // "123.0"

CurrentCultureสำหรับการจัดรูปแบบนี้เป็นวิธีการที่จะใช้เสมอ วัฒนธรรมบางอย่างจะเปลี่ยนไป.,

ตอบคำถามต้นฉบับ:

ทางออกที่ง่ายที่สุดมาจาก @Andrew ( ที่นี่ ) ดังนั้นโดยส่วนตัวฉันจะใช้สิ่งนี้:

var number = 123.46;
String.Format(number % 1 == 0 ? "{0:0}" : "{0:0.00}", number)

20
ตอนแรกฉันคิดว่านี่น่าจะเป็นคำตอบจนกว่าฉันจะอ่านคำถามเดิมซ้ำหลายครั้ง OP ไม่ชัดเจนทั้งหมดในสิ่งที่เขาต้องการ แต่ดูเหมือนว่าเขาต้องการทศนิยม 2 ตำแหน่งเสมอถ้ามีคนป้อนเศษส่วน ดังนั้นถ้ามีคนป้อน 1.1 แล้วเขาต้องการ 1.10; รหัสนี้จะไม่ทำอย่างนั้น
— Doug S

40
โอ๊ะฉันอ่านอีกครั้งและคุณพูดถูก ดังนั้นนี่ไม่ใช่คำตอบที่ถูกต้อง แต่อย่างน้อยบางคนอาจพบว่ามีประโยชน์
— Gh61

สิ่งที่ OP ต้องการสามารถทำได้ด้วย: stackoverflow.com/a/33180829/2321042
— Andrew

ฉันเพิ่งพบว่ามีประโยชน์และ (ค่อนข้าง) ตรงกับสิ่งที่ BoundField ใน GridView ทำกับ SqlDouble และไม่มีรูปแบบคำสั่ง คุณต้องระบุจำนวนสูงสุดที่คุณจะแสดง (เทียบกับ BoundField ยินดีที่ได้แสดงมากหรือน้อยตามที่คุณต้องการ)
— fortboise

Yup สิ่งนี้มีประโยชน์ แต่จะแสดงทศนิยมแค่สองตำแหน่งถ้ามีทศนิยมอย่างไร คือถ้ามันเป็นจำนวนเต็มแล้วไม่แสดงทศนิยม?
— ไนเจล Fds

64

นี่เป็นกรณีการใช้รูปแบบตัวเลขลอยตัวทั่วไป

น่าเสียดายที่สตริงรูปแบบตัวอักษรทั้งหมดในตัว (เช่น F, G, N) ทั้งหมดจะไม่สามารถทำสิ่งนี้ได้โดยตรง
ตัวอย่างเช่นnum.ToString("F2")จะแสดงตำแหน่งทศนิยม 2 ตำแหน่ง123.40เสมอ

คุณจะต้องใช้0.##รูปแบบแม้ว่ามันจะดูเป็นเรื่องเล็กน้อย

ตัวอย่างโค้ดแบบสมบูรณ์:

double a = 123.4567;
double b = 123.40;
double c = 123.00;

string sa = a.ToString("0.##"); // 123.46
string sb = b.ToString("0.##"); // 123.4
string sc = c.ToString("0.##"); // 123

7
แต่เขาต้องการ 123.40 ไม่ใช่ 123.4
— Andrew

8
ไม่แก้คำถามนี้ แต่แก้ปัญหาของฉัน ฉันโหวตสิ่งนี้เพื่อให้ทุกคนได้เห็น
— Emad

46

คำถามเก่า แต่ฉันต้องการเพิ่มตัวเลือกที่ง่ายที่สุดในความคิดของฉัน

โดยไม่มีตัวคั่นหลักพัน:

value.ToString(value % 1 == 0 ? "F0" : "F2")

ด้วยตัวคั่นหลักพัน:

value.ToString(value % 1 == 0 ? "N0" : "N2")

เหมือนกัน แต่กับString รูปแบบ :

String.Format(value % 1 == 0 ? "{0:F0}" : "{0:F2}", value) // Without thousands separators
String.Format(value % 1 == 0 ? "{0:N0}" : "{0:N2}", value) // With thousands separators

หากคุณต้องการมันในหลาย ๆ ที่ฉันจะใช้ตรรกะนี้ในวิธีการขยาย :

public static string ToCoolString(this decimal value)
{
    return value.ToString(value % 1 == 0 ? "N0" : "N2"); // Or F0/F2 ;)
}

28

ลอง

double myPrice = 123.0;

String.Format(((Math.Round(myPrice) == myPrice) ? "{0:0}" : "{0:0.00}"), myPrice);

5
string.Format ((หมายเลข% 1) == 0? "{0: 0}": "{0: 0.00}", ตัวเลข);
— Patrick

8

ฉันไม่รู้ว่าจะใส่เงื่อนไขในตัวระบุรูปแบบอย่างไร แต่คุณสามารถเขียนฟอร์แมตของคุณเอง:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
               // all of these don't work
            Console.WriteLine("{0:C}", 10);
            Console.WriteLine("{0:00.0}", 10);
            Console.WriteLine("{0:0}", 10);
            Console.WriteLine("{0:0.00}", 10);
            Console.WriteLine("{0:0}", 10.0);
            Console.WriteLine("{0:0}", 10.1);
            Console.WriteLine("{0:0.00}", 10.1);

          // works
            Console.WriteLine(String.Format(new MyFormatter(),"{0:custom}", 9));
            Console.WriteLine(String.Format(new MyFormatter(),"{0:custom}", 9.1));
            Console.ReadKey();
        }
    }

    class MyFormatter : IFormatProvider, ICustomFormatter
    {
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            switch (format.ToUpper())
            {
                case "CUSTOM":
                    if (arg is short || arg is int || arg is long)
                        return arg.ToString();
                    if (arg is Single || arg is Double)
                        return String.Format("{0:0.00}",arg);
                    break;
                // Handle other
                default:
                    try
                    {
                        return HandleOtherFormats(format, arg);
                    }
                    catch (FormatException e)
                    {
                        throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e);
                    }
            }
            return arg.ToString(); // only as a last resort
        }

        private string HandleOtherFormats(string format, object arg)
        {
            if (arg is IFormattable)
                return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
            if (arg != null)
                return arg.ToString();
            return String.Empty;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter))
                return this;
            return null;
        }
    }
}

6

นี่คือทางเลือกของวิธีของ Uwe Keim ซึ่งจะยังคงใช้วิธีการเดิม:

var example1 = MyCustomFormat(123.1);  // Output: 123.10
var example2 = MyCustomFormat(123.95); // Output: 123.95
var example3 = MyCustomFormat(123);    // Output: 123

ด้วยMyCustomFormatการเป็นสิ่งที่ชอบ:

public static string MyCustomFormat( double myNumber )
{
    var str (string.Format("{0:0.00}", myNumber))
    return (str.EndsWith(".00") ? str.Substring(0, strLastIndexOf(".00")) : str;
}

สิ่งนี้ไม่ได้ผลสำหรับฉันเพราะดูเหมือนว่า TrimEnd จะใช้ตัวอักษรหลายตัวเช่น {',', '.', ''} แทนที่จะเป็นสตริงเช่น ".00" - ดูmsdn.microsoft.com/en-us/ library / system.string.trimend.aspx
— user1069816

คุณพูดถูก - ไม่แน่ใจว่าฉันคิดถึงสิ่งนั้นอย่างไร ฉันได้รับการอัพเดตให้ทำงานอย่างถูกต้อง
— Steve

5
ทั้งนี้ขึ้นอยู่กับหัวข้อปัจจุบันของตัวคั่นทศนิยมอาจจะไม่CurrentCulture .ยกเว้นว่าCultureInfo.InvariantCultureใช้กับstring.Formatคุณจะต้องตรวจสอบค่าของCultureInfo.NumberFormat.NumberDecimalSeparatorซึ่งค่อนข้างไม่เหมาะสม
— Groo

6

ง่าย ๆ หนึ่งบรรทัดรหัส:

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}

ปัญหานี้คือถ้ามันทำงานที่ตัวคั่นทศนิยมเป็นเครื่องหมายจุลภาค ตรวจสอบความคิดเห็นสำหรับคำตอบนี้
— แอนดรู

6

หากโปรแกรมของคุณต้องการเรียกใช้อย่างรวดเร็วให้เรียกค่า call.ToString (formatString) เพื่อประสิทธิภาพการจัดรูปแบบสตริงที่เร็วขึ้น ~ 35% เทียบกับ $ "{value: formatString}" และ string.Format (formatString, value)

ข้อมูล

ประสิทธิภาพการจัดรูปแบบสตริง C # - VS2017 15.4.5

รหัส

using System;
using System.Diagnostics;

public static class StringFormattingPerformance
{
   public static void Main()
   {
      Console.WriteLine("C# String Formatting Performance");
      Console.WriteLine("Milliseconds Per 1 Million Iterations - Best Of 5");
      long stringInterpolationBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return $"{randomDouble:0.##}";
          });
      long stringDotFormatBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return string.Format("{0:0.##}", randomDouble);
          });
      long valueDotToStringBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return randomDouble.ToString("0.##");
          });
      Console.WriteLine(
$@"            $""{{value:formatString}}"": {stringInterpolationBestOf5} ms
 string.Format(formatString, value): {stringDotFormatBestOf5} ms
       value.ToString(formatString): {valueDotToStringBestOf5} ms");
   }

   private static long Measure1MillionIterationsBestOf5(
       Func<double, string> formatDoubleUpToTwoDecimalPlaces)
   {
      long elapsedMillisecondsBestOf5 = long.MaxValue;
      for (int perfRunIndex = 0; perfRunIndex < 5; ++perfRunIndex)
      {
         var random = new Random();
         var stopwatch = Stopwatch.StartNew();
         for (int i = 0; i < 1000000; ++i)
         {
            double randomDouble = random.NextDouble();
            formatDoubleUpToTwoDecimalPlaces(randomDouble);
         }
         stopwatch.Stop();
         elapsedMillisecondsBestOf5 = Math.Min(
            elapsedMillisecondsBestOf5, stopwatch.ElapsedMilliseconds);
      }
      return elapsedMillisecondsBestOf5;
   }
}

รหัสออก

C# String Formatting Performance
Milliseconds Per 1 Million Iterations - Best Of 5
            $"{value:formatString}": 419 ms
 string.Format(formatString, value): 419 ms
       value.ToString(formatString): 264 ms

อ้างอิง

สตริงรูปแบบตัวเลขแบบกำหนดเอง [docs.microsoft.com]

แผนภูมิแท่งแผนภูมิ Qt ตัวอย่าง [doc.qt.io]


5

ฉันกลัวว่าจะไม่มีรูปแบบในตัวที่จะทำเช่นนี้ คุณจะต้องใช้รูปแบบที่แตกต่างกันขึ้นอยู่กับว่าค่านั้นเป็นจำนวนเต็มหรือไม่ หรือจัดรูปแบบเป็นทศนิยม 2 ตำแหน่งเสมอและจัดการสตริงในภายหลังเพื่อลบส่วนท้าย ".00"


4

หากไม่มีคำตอบอื่นใดที่เหมาะกับคุณอาจเป็นเพราะคุณผูกพันการContentPropertyควบคุมในOnLoadฟังก์ชันซึ่งหมายความว่าสิ่งนี้จะไม่ทำงาน:

private void UserControl_Load(object sender, RoutedEventArgs e)
{
  Bind.SetBindingElement(labelName, String.Format("{0:0.00}", PropertyName), Label.ContentProperty) 
}

วิธีแก้ปัญหานั้นง่าย: มีContentStringFormatคุณสมบัติใน xaml ดังนั้นเมื่อคุณสร้างฉลากให้ทำสิ่งนี้:

//if you want the decimal places definite
<Label Content="0" Name="labelName" ContentStringFormat="0.00"/>

หรือ

//if you want the decimal places to be optional
<Label Content="0" Name="labelName" ContentStringFormat="0.##"/>

3

บางสิ่งเช่นนี้ก็ใช้ได้เช่นกัน:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")

นั่นให้เปอร์เซ็นต์


2

หากต้องการทำให้รหัสชัดเจนยิ่งขึ้นที่ Kahia เขียนไว้ (ชัดเจน แต่จะยุ่งยากเมื่อคุณต้องการเพิ่มข้อความเพิ่มเติม) ... ลองใช้วิธีแก้ปัญหาง่ายๆนี้

if (Math.Round((decimal)user.CurrentPoints) == user.CurrentPoints)
     ViewBag.MyCurrentPoints = String.Format("Your current Points: {0:0}",user.CurrentPoints);
else
     ViewBag.MyCurrentPoints = String.Format("Your current Points: {0:0.0}",user.CurrentPoints);

ฉันต้องเพิ่ม cast พิเศษ (ฐานสิบ) เพื่อให้ Math.Round เปรียบเทียบตัวแปรทศนิยมสองตัว


1

สิ่งนี้ได้ผลสำหรับฉัน!

String amount= "123.0000";
String.Format("{0:0.##}", amount);      // "123.00"

1
ไม่ได้ผล เขาต้องการให้ 123.00 แสดงเป็น "123" และ 123.50 เป็น "123.50"
— Andrew

1

เมื่อจัดการกับทศนิยมที่มาจากฐานข้อมูล SQL (T-) คุณต้องการแปลงทศนิยมที่ไม่มีค่าและไม่สามารถลบได้ด้วยตำแหน่งทศนิยมสิบตำแหน่งและสามารถตรวจสอบรหัสได้อย่างง่ายดายตามคำจำกัดความของตาราง - และแน่นอนแสดง จำนวนทศนิยมที่ถูกต้องให้กับผู้ใช้

น่าเสียดายที่ Entity Framework ไม่ได้แปลงอะไรบางอย่างเช่น SQL decimal(18,2)ไปเป็น. NET เทียบเท่ากับจำนวนทศนิยมเท่าเดิมโดยอัตโนมัติ คุณต้องตัดทอนทศนิยมด้วยตนเอง

ดังนั้นฉันทำอย่างนี้:

public static class Extensions
{
    public static string ToStringDecimal(this decimal d, byte decimals)
    {
        var fmt = (decimals>0) ? "0." + new string('0', decimals) : "0";
        return d.ToString(fmt);
    }

    public static string ToStringDecimal(this decimal? d, byte decimals)
    {
        if (!d.HasValue) return "";
        return ToStringDecimal(d.Value, decimals);
    }
}

ตัวอย่างการใช้งาน:

void Main()
{
    decimal d = (decimal)1.2345;
    decimal? d2 = null; 

    Console.WriteLine(d.ToStringDecinal(2)); // prints: "1.23" (2 decimal places)
    Console.WriteLine(d.ToStringDecinal(0)); // prints: "1" (show integer number)
    Console.WriteLine(d2.ToStringDecimal(2)); // prints: "" (show null as empty string)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.