Menggunakan String Format untuk menampilkan desimal hingga 2 tempat atau integer sederhana

291

Saya telah mendapatkan bidang harga untuk ditampilkan yang kadang-kadang bisa 100 atau 100,99 atau 100,9. Yang saya inginkan adalah menampilkan harga di 2 tempat desimal hanya jika desimalnya dimasukkan untuk harga itu, misalnya jika angka 100 maka seharusnya hanya 100 menunjukkan 100 bukan 100,00 dan jika harga 100,2 itu harus menampilkan 100,20 sama untuk 100,22 harus sama. Saya mencari di Google dan menemukan beberapa contoh tetapi mereka tidak cocok persis dengan apa yang saya inginkan:

// 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"
Tuan A
sumber
4
kemungkinan duplikat .net Format desimal ke dua tempat atau seluruh angka
Binary Worrier
1
RE: "Yang saya inginkan adalah menampilkan harga di 2 tempat desimal hanya jika desimal dimasukkan untuk harga itu" - jadi jika pengguna mengetik "100.00" Anda ingin menampilkan "100.00", tetapi jika mereka mengetik "100" Anda hanya ingin menampilkan "100"? - tipe nomor hanya melacak nilai nomor - bukan yang mana dari angka tidak signifikan yang dimasukkan oleh pengguna dan yang bukan - untuk itu Anda harus menggunakan string.
BrainSlugs83
2
@ BinaryWorrier Saya pikir pertanyaan ini mungkin merupakan duplikat, tetapi memiliki jawaban yang jauh lebih baik dan lebih lengkap. IMO yang lain harus ditandai sebagai duplikat dari yang ini.
Ryan Gates
tambahkan saja .Replace (". 00", "")
Dave Sumter

Jawaban:

156

Cara yang salah adalah:

var my = DoFormat(123.0);

Dengan DoFormatmenjadi sesuatu seperti:

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

Tidak elegan tetapi bekerja untuk saya dalam situasi serupa di beberapa proyek.

Uwe Keim
sumber
6
Ini sebenarnya bukan pertanyaan yang ditanyakan - tetapi seandainya - mengapa tidak hanya menggunakan string.Format ("{0: 0.00}"). Ganti ("00", "")?
BrainSlugs83
18
@ BrainSlugs83: tergantung pada utas saat ini CurrentCulture, pemisah desimal mungkin tidak .. Kecuali CultureInfo.InvariantCulturedigunakan string.Format, Anda harus memeriksa nilainya CultureInfo.NumberFormat.NumberDecimalSeparator, dan itu akan menjadi PITA nyata. :)
Groo
@Uwe Keim Bagaimana jika saya memiliki 60000int dan saya menginginkannya 60.000?
Prashant Pimpale
Jawaban ini adalah kasus "menciptakan kembali roda persegi". Tidak memperhitungkan budaya akun atau fakta bahwa ini sudah ditangani oleh .NET.
bytedev
523

Maaf karena mengaktifkan kembali pertanyaan ini, tetapi saya tidak menemukan jawaban yang tepat di sini.

Dalam memformat angka Anda dapat menggunakan 0sebagai tempat wajib dan# sebagai tempat opsional.

Begitu:

// 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"

Anda juga dapat menggabungkan 0dengan #.

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"

Untuk metode formating ini selalu digunakan CurrentCulture. Untuk beberapa Budaya .akan diubah menjadi, .

Jawab pertanyaan awal:

Solusi paling sederhana datang dari @Andrew (di sini ). Jadi saya pribadi akan menggunakan sesuatu seperti ini:

var number = 123.46;
String.Format(number % 1 == 0 ? "{0:0}" : "{0:0.00}", number)
Gh61
sumber
20
Pada awalnya, saya pikir ini adalah jawabannya, sampai saya membaca ulang pertanyaan aslinya beberapa kali. OP tidak sepenuhnya jelas apa yang sebenarnya ia inginkan, tetapi tampaknya ia selalu menginginkan 2 tempat desimal jika seseorang memasuki fraksi. Jadi, jika seseorang memasukkan 1,1 maka ia ingin 1,10; kode ini tidak akan melakukan itu.
Doug S
40
Ups, saya membacanya lagi dan Anda benar. Jadi, ini bukan jawaban yang tepat tetapi setidaknya seseorang mungkin menganggap ini berguna.
Gh61
Apa yang dibutuhkan OP dapat dicapai dengan ini: stackoverflow.com/a/33180829/2321042
Andrew
Saya baru saja menemukannya berguna, dan (agak) cocok dengan apa yang BoundField di GridView lakukan dengan SqlDouble dan tidak ada instruksi format. Anda harus menunjukkan jumlah maksimum yang akan ditampilkan. (Vs. BoundField, senang menunjukkan sebanyak atau sesedikit yang Anda suka)
fortboise
Yup ini berguna, tetapi bagaimana hanya menampilkan dua desimal jika desimal ada? yaitu jika itu bilangan bulat maka jangan tampilkan desimal?
Nigel Fds
64

Ini adalah kasus penggunaan pemformatan angka mengambang yang umum.

Sayangnya, semua string format satu huruf bawaan (mis. F, G, N) tidak akan mencapainya secara langsung.
Misalnya, num.ToString("F2")akan selalu menampilkan 2 tempat desimal seperti123.40 .

Anda harus menggunakan 0.##pola walaupun terlihat sedikit bertele-tele.

Contoh kode lengkap:

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
detale
sumber
7
Tapi dia ingin 123,40, bukan 123,4.
Andrew
8
Bukan memecahkan pertanyaan ini tetapi menyelesaikan pertanyaan saya. Saya membenarkan hal ini agar semua orang dapat melihatnya.
Emad
46

Pertanyaan lama tapi saya ingin menambahkan opsi paling sederhana menurut saya.

Tanpa ribuan pemisah:

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

Dengan ribuan pemisah:

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

Sama tetapi dengan String.Format :

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

Jika Anda membutuhkannya di banyak tempat , saya akan menggunakan logika ini dalam metode ekstensi :

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

mencoba

double myPrice = 123.0;

String.Format(((Math.Round(myPrice) == myPrice) ? "{0:0}" : "{0:0.00}"), myPrice);
Yahia
sumber
5
string.Format ((angka% 1) == 0? "{0: 0}": "{0: 0.00}", number);
Patrick
8

Saya tidak tahu bagaimana cara memasukkan syarat dalam format specifier, tetapi Anda dapat menulis formatter Anda sendiri:

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;
        }
    }
}
Tim Hoolihan
sumber
6

Berikut adalah alternatif untuk metode Uwe Keim, yang masih akan mempertahankan panggilan metode yang sama:

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

Dengan MyCustomFormatmenjadi sesuatu seperti:

public static string MyCustomFormat( double myNumber )
{
    var str (string.Format("{0:0.00}", myNumber))
    return (str.EndsWith(".00") ? str.Substring(0, strLastIndexOf(".00")) : str;
}
Steve
sumber
Ini tidak berfungsi untuk saya karena tampaknya TrimEnd mengambil array karakter seperti {',', '.', ''} Daripada string seperti ".00" - Lihat msdn.microsoft.com/en-us/ library / system.string.trimend.aspx
user1069816
Anda benar - tidak yakin bagaimana saya melewatkannya. Saya telah memperbarui agar berfungsi dengan benar.
Steve
5
Bergantung pada utas saat ini CurrentCulture, pemisah desimal mungkin tidak .. Kecuali jika CultureInfo.InvariantCulturedigunakan string.Format, Anda harus memeriksa nilai CultureInfo.NumberFormat.NumberDecimalSeparator, yang agak tidak akurat.
Groo
6

Kode satu baris sederhana:

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}
Philip Stuyck
sumber
Masalah dengan ini adalah jika dijalankan di mana pemisah desimal adalah koma. Periksa komentar untuk jawaban ini .
Andrew
6

Jika program Anda perlu berjalan cepat, panggil value.ToString (formatString) untuk ~ 35% lebih cepat memformat kinerja string relatif ke $ "{value: formatString}" dan string.Format (formatString, nilai).

Data

C # Kinerja Pemformatan String - VS2017 15.4.5

Kode

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

Output Kode

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

Referensi

String Format Numerik Ubahsuaian [docs.microsoft.com]

Qt Charts Contoh BarChart [doc.qt.io]

Neil Justice
sumber
5

Saya khawatir tidak ada format bawaan yang akan melakukan ini. Anda harus menggunakan format yang berbeda tergantung pada apakah nilainya bilangan bulat atau tidak. Atau selalu memformat ke 2 tempat desimal, dan memanipulasi string sesudahnya untuk menghapus "00".

Nikki Locke
sumber
4

Jika tidak ada jawaban lain yang bekerja untuk Anda, itu mungkin karena Anda mengikat ContentPropertykontrol pada OnLoadfungsi, yang berarti ini tidak akan berfungsi:

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

Solusinya sederhana: ada ContentStringFormatproperti di xaml. Jadi ketika Anda membuat label, lakukan ini:

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

Atau

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

sesuatu seperti ini akan bekerja juga:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")
ekki
sumber
Itu memberi persen?
3

Mencoba:

String.Format("{0:0.00}", Convert.ToDecimal(totalPrice));
pengguna1067656
sumber
2

Untuk membuat kode lebih jelas bahwa Kahia menulis (jelas tapi menjadi rumit ketika Anda ingin menambahkan lebih banyak teks ke dalamnya) ... coba solusi sederhana ini.

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

Saya harus menambahkan pemeran ekstra (desimal) untuk memiliki Math.Round membandingkan dua variabel desimal.

coding_is_fun
sumber
1

Ini berhasil untuk saya!

String amount= "123.0000";
String.Format("{0:0.##}", amount);      // "123.00"
Edwin Ikechukwu Okonkwo
sumber
1
Itu tidak berhasil. Dia ingin 123.00 ditampilkan sebagai "123" dan 123.50 sebagai "123.50".
Andrew
1

Ketika berhadapan dengan desimal yang berasal dari database SQL (T-), Anda ingin dapat mengonversi desimal nullable dan non-nullable dengan x tempat desimal dan dapat meninjau kode dengan mudah terhadap definisi tabel Anda - dan tentu saja, tampilkan jumlah desimal yang tepat bagi pengguna.

Sayangnya, Entity Framework tidak secara otomatis mengonversi sesuatu seperti SQL decimal(18,2) menjadi .NET yang setara dengan jumlah tempat desimal yang sama (karena hanya ada desimal dengan presisi penuh yang tersedia). Anda harus memotong tempat desimal secara manual.

Jadi, saya melakukannya dengan cara ini:

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

Contoh penggunaan:

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)
}
Mat
sumber