Użycie formatu ciągu do wyświetlenia po przecinku do 2 miejsc lub prostej liczby całkowitej


291

Mam pole ceny do wyświetlenia, które czasami może wynosić 100, 100,99 lub 100,9. Chcę wyświetlać cenę z dokładnością do 2 miejsc po przecinku tylko wtedy, gdy liczby dziesiętne są wprowadzane dla tej ceny, na przykład jeśli jest to 100, więc powinna tylko pokaż 100, a nie 100,00, a jeśli cena wynosi 100,2, powinna wyświetlić 100,20 podobnie dla 100,22 powinna być taka sama. Przeszukałem Google i natknąłem się na kilka przykładów, ale nie pasowały one dokładnie do tego, czego chciałem:

// 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: „Chcę wyświetlać cenę z dokładnością do 2 miejsc po przecinku tylko wtedy, gdy liczby dziesiętne są wprowadzane dla tej ceny” - więc jeśli użytkownik wpisze „100,00”, chcesz wyświetlić „100,00”, ale jeśli wpisze „100” chcesz pokazać tylko „100”? - typy liczb śledzą tylko wartość liczby - nie które z nieistotnych cyfr zostały wprowadzone przez użytkownika, a które nie - w tym celu należy użyć ciągu znaków.
— BrainSlugs83

2
@BinaryWorrier Myślę, że to pytanie może być duplikatem, ale ma znacznie lepsze i pełniejsze odpowiedzi. IMO drugi należy oznaczyć jako jego duplikat.
— Ryan Gates

wystarczy dodać .Replace („. 00”, „”)
— Dave Sumter

Odpowiedzi:


155

Nieelegancki sposób to:

var my = DoFormat(123.0);

Z DoFormatbycia coś takiego:

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

Nie elegancki, ale działa w podobnych sytuacjach w niektórych projektach.


6
To nie jest tak naprawdę pytanie, które zostało zadane - ale gdyby tak było - dlaczego po prostu nie użyć string.Format („{0: 0.00}”). Zastąpić („. 00”, „”)?
— BrainSlugs83

18
@ BrainSlugs83: w zależności od bieżącego wątku CurrentCultureseparatorem dziesiętnym może nie być .. Jeśli nie CultureInfo.InvariantCulturejest używany string.Format, musisz sprawdzić wartość CultureInfo.NumberFormat.NumberDecimalSeparator, a to byłaby prawdziwa PITA. :)
— Groo

@ Uwe Keim Co jeśli mam 60000int i chcę, żeby tak było 60.000?
— Prashant Pimpale

Ta odpowiedź to przypadek „wynalezienia kwadratowego koła”. Nie bierze pod uwagę kultury ani faktu, że była już obsługiwana przez .NET.
— bytedev

523

Przepraszamy za reaktywację tego pytania, ale nie znalazłem tutaj właściwej odpowiedzi.

Przy formatowaniu liczb możesz użyć 0jako miejsca obowiązkowego i #opcjonalnego.

Więc:

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

Możesz także łączyć 0z #.

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"

W tym przypadku zawsze używana jest metoda formatowania CurrentCulture. Niektóre kultury .zostaną zmienione na ,.

Odpowiedź na oryginalne pytanie:

Najprostsze rozwiązanie pochodzi z @Andrew ( tutaj ). Więc osobiście użyłbym czegoś takiego:

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

20
Na początku myślałem, że to powinna być odpowiedź, dopóki kilkakrotnie nie przeczytałem oryginalnego pytania. OP nie jest do końca jasne, czego dokładnie chce, ale wydaje się, że zawsze chce 2 miejsc po przecinku, jeśli ktoś wpisze ułamek. Więc jeśli ktoś wejdzie w 1.1, to będzie chciał 1.10; ten kod by tego nie zrobił.
— Doug S

40
Ups, przeczytałem to jeszcze raz i masz rację. To nie jest odpowiednia odpowiedź, ale przynajmniej ktoś może uznać to za przydatne.
— Gh61

Co potrzebne OP można osiągnąć dzięki temu: stackoverflow.com/a/33180829/2321042
— Andrew

Po prostu uznałem, że jest to użyteczne i (w pewnym stopniu) dopasowanie tego, co BoundField w GridView robi z instrukcją SqlDouble i bez formatu. Musisz podać maksymalną liczbę wyświetlanych znaków. (Przeciwko BoundField, chętnie pokazuję tyle, ile chcesz)
— fortboise

Tak, to było przydatne, ale jak pokazać tylko dwa miejsca po przecinku, jeśli występuje po przecinku? tzn. jeśli jest to liczba całkowita, to nie wyświetlaj miejsc po przecinku?
— Nigel Fds,

64

Jest to częsty przypadek użycia liczb zmiennoprzecinkowych.

Niestety, wszystkie wbudowane łańcuchy formatu liter (np. F, G, N) nie osiągną tego bezpośrednio.
Na przykład num.ToString("F2")zawsze pokaże 2 miejsca po przecinku, takie jak 123.40.

Będziesz musiał użyć 0.##wzoru, nawet jeśli wygląda na trochę gadatliwego.

Kompletny przykład kodu:

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
Ale chce 123,40, a nie 123,4.
— Andrew

8
Nie rozwiązując tego pytania, ale rozwiązując moje. Głosuję za tym, aby wszyscy inni mogli to zobaczyć.
— Emad,

46

Stare pytanie, ale moim zdaniem chciałem dodać najprostszą opcję.

Bez tysięcy separatorów:

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

Z tysiącami separatorów:

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

To samo, ale z 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

Jeśli potrzebujesz go w wielu miejscach , użyłbym tej logiki w metodzie rozszerzenia :

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

28

próbować

double myPrice = 123.0;

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

5
string.Format ((liczba% 1) == 0? "{0: 0}": "{0: 0,00}", liczba);
— Patrick

8

Zresztą nie wiem, jak ustawić warunek w specyfikatorze formatu, ale możesz napisać własny formatyzator:

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

Oto alternatywa dla metody Uwe Keima, która nadal utrzymywałaby to samo wywołanie metody:

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

Z MyCustomFormatbycia coś takiego:

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

Nie działało to dla mnie, ponieważ wydaje się, że TrimEnd pobiera tablicę znaków takich jak {',', '.', ''} Zamiast łańcucha takiego jak ".00" - patrz msdn.microsoft.com/en-us/ biblioteka / system.string.trimend.aspx
— użytkownik1069816

Masz rację - nie jestem pewien, jak mi tego brakowało. Zaktualizowałem, aby działał poprawnie.
— Steve

5
W zależności od bieżącego wątku CurrentCultureseparatorem dziesiętnym może nie być .. O ile nie CultureInfo.InvariantCulturejest używane z string.Format, musisz sprawdzić wartość CultureInfo.NumberFormat.NumberDecimalSeparator, która jest raczej nieelegancka.
— Groo

6

Prosty kod jednoliniowy:

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

Problem polega na tym, że jest uruchamiany tam, gdzie separatorem dziesiętnym jest przecinek. Sprawdź komentarze do tej odpowiedzi .
— Andrew

6

Jeśli twój program musi działać szybko, wywołaj value.ToString (formatString), aby uzyskać ~ 35% szybszą wydajność formatowania łańcucha w stosunku do $ „{wartość: formatString}” i string.Format (formatString, wartość).

Dane

Wydajność formatowania ciągów C # - VS2017 15.4.5

Kod

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

Kod wyjściowy

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

Bibliografia

Niestandardowe ciągi formatu liczbowego [docs.microsoft.com]

Przykład wykresów Qt BarChart [doc.qt.io]


5

Obawiam się, że nie ma wbudowanego formatu, który to zrobiłby. Będziesz musiał użyć innego formatu w zależności od tego, czy wartość jest liczbą całkowitą, czy nie. Lub zawsze formatuj do 2 miejsc po przecinku, a następnie manipuluj ciągiem, aby usunąć końcowe „.00”.


4

Jeśli żadna z pozostałych odpowiedzi nie działa dla Ciebie, może to wynikać z tego, że wiążesz ContentPropertykontrolkę w OnLoadfunkcji, co oznacza, że ​​to nie zadziała:

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

Rozwiązanie jest proste: ContentStringFormatw xaml jest właściwość. Więc kiedy tworzysz etykietę, zrób to:

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

Lub

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

3

coś takiego też będzie działać:

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

To daje procent?


2

Aby kod był bardziej przejrzysty, który napisał Kahia (jest przejrzysty, ale staje się trudny, gdy chcesz dodać do niego więcej tekstu) ... wypróbuj to proste rozwiązanie.

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

Musiałem dodać dodatkowy rzut (dziesiętny), aby Math.Round porównał dwie zmienne dziesiętne.


1

To zadziałało dla mnie!

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

1
To nie działa. Chce, aby 123,00 było wyświetlane jako „123”, a 123,50 jako „123,50”.
— Andrew

1

W przypadku liczb dziesiętnych pochodzących z bazy danych (T-) SQL chcesz mieć możliwość konwertowania dziesiętnych i zerowalnych miejsc dziesiętnych z x miejscami dziesiętnymi, a także mieć możliwość łatwego przeglądania kodu w porównaniu z definicjami tabel - i oczywiście wyświetlanie odpowiednia liczba miejsc po przecinku dla użytkownika.

Niestety, Entity Framework nie konwertuje automatycznie czegoś takiego jak SQL decimal(18,2)na ekwiwalent .NET z taką samą liczbą miejsc dziesiętnych (ponieważ dostępny jest tylko ułamek dziesiętny z pełną dokładnością). Musisz ręcznie obciąć miejsca dziesiętne.

Zrobiłem to w ten sposób:

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

Przykładowe użycie:

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)
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.