การใช้รูปแบบสตริงเพื่อแสดงทศนิยมได้ถึง 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.