Verwenden des Zeichenfolgenformats zum Anzeigen von Dezimalstellen bis zu 2 Stellen oder einer einfachen Ganzzahl

291

Ich muss ein Preisfeld anzeigen, das manchmal entweder 100 oder 100,99 oder 100,9 sein kann. Ich möchte den Preis nur dann in 2 Dezimalstellen anzeigen, wenn die Dezimalstellen für diesen Preis eingegeben werden, zum Beispiel, wenn es 100 ist, sollte es nur so sein zeige 100 nicht 100.00 und wenn der Preis 100.2 ist, sollte es 100.20 ähnlich anzeigen, für 100.22 sollte es gleich sein. Ich habe gegoogelt und bin auf einige Beispiele gestoßen, aber sie passten nicht genau zu dem, was ich wollte:

// 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"
Herr A.
quelle
4
Mögliches Duplikat von .net Format dezimal auf zwei Stellen oder eine ganze Zahl
Binary Worrier
1
RE: "Ich möchte den Preis nur dann in 2 Dezimalstellen anzeigen, wenn die Dezimalstellen für diesen Preis eingegeben wurden." Wenn der Benutzer also "100.00" eingibt, möchten Sie "100.00" anzeigen, aber wenn er "100" eingibt. du willst nur "100" zeigen? - Zahlentypen verfolgen nur den Wert der Zahl - nicht welche der unbedeutenden Ziffern von einem Benutzer eingegeben wurden und welche nicht - dafür müssen Sie eine Zeichenfolge verwenden.
BrainSlugs83
2
@BinaryWorrier Ich denke, dass diese Frage ein Duplikat ist, aber sie hat viel bessere und vollständigere Antworten. IMO sollte der andere als Duplikat von diesem markiert werden.
Ryan Gates
Fügen Sie einfach .Replace (". 00", "") hinzu
Dave Sumter

Antworten:

156

Ein uneleganter Weg wäre:

var my = DoFormat(123.0);

Mit DoFormatso etwas wie:

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

Nicht elegant, aber in einigen Projekten in ähnlichen Situationen für mich zu arbeiten.

Uwe Keim
quelle
6
Dies ist nicht wirklich die Frage, die gestellt wurde - aber war es das - warum nicht einfach string.Format ("{0: 0.00}") verwenden. Ersetzen (". 00", "")?
BrainSlugs83
18
@ BrainSlugs83: Abhängig vom aktuellen Thread ist das CurrentCultureDezimaltrennzeichen möglicherweise nicht vorhanden .. Wenn CultureInfo.InvariantCulturees nicht mit verwendet wird string.Format, müssten Sie den Wert von überprüfen CultureInfo.NumberFormat.NumberDecimalSeparator, und das wäre eine echte PITA. :)
Groo
@Uwe Keim Was ist, wenn ich 60000int habe und ich möchte, dass es so ist 60.000?
Prashant Pimpale
Diese Antwort ist ein Fall von "Neuerfindung eines quadratischen Rades". Berücksichtigt nicht die Kultur oder die Tatsache, dass dies bereits von .NET erledigt wurde.
bytedev
523

Entschuldigung für die Reaktivierung dieser Frage, aber ich habe hier nicht die richtige Antwort gefunden.

Bei der Formatierung von Zahlen können Sie diese 0als obligatorischen Ort und #als optionalen Ort verwenden.

So:

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

Sie können auch kombinieren 0mit #.

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"

Für diese Formatierungsmethode wird immer verwendet CurrentCulture. Für einige Kulturen .wird auf geändert ,.

Antwort auf die ursprüngliche Frage:

Die einfachste Lösung kommt von @Andrew ( hier ). Also würde ich persönlich so etwas verwenden:

var number = 123.46;
String.Format(number % 1 == 0 ? "{0:0}" : "{0:0.00}", number)
Gh61
quelle
20
Zuerst dachte ich, dies sollte die Antwort sein, bis ich die ursprüngliche Frage mehrmals neu las. Dem OP ist nicht ganz klar, was er genau will, aber es scheint, dass er immer 2 Dezimalstellen will, wenn jemand einen Bruch eingibt. Wenn also jemand 1.1 eingegeben hat, möchte er 1.10; Dieser Code würde das nicht tun.
Doug S
40
Ups, ich habe es noch einmal gelesen und du hast recht. Das ist also nicht die richtige Antwort, aber zumindest könnte dies jemand nützlich finden.
Gh61
Was OP benötigt wird, kann damit erreicht werden: stackoverflow.com/a/33180829/2321042
Andrew
Ich fand es gerade nützlich und (etwas) übereinstimmend, was ein BoundField in einer GridView mit einem SqlDouble und ohne Formatierungsanweisung macht. Sie müssen die maximale Anzahl angeben, die Sie anzeigen möchten. (Vs. BoundField, glücklich, so viele oder so wenige zu zeigen, wie Sie
möchten
Ja, das war nützlich, aber wie kann man nur zwei Dezimalstellen anzeigen, wenn eine Dezimalstelle vorhanden ist? dh wenn es eine ganze Zahl ist, dann keine Dezimalstellen anzeigen?
Nigel Fds
64

Dies ist ein gängiger Anwendungsfall für die Formatierung von schwebenden Zahlen.

Leider erreichen dies nicht alle integrierten Zeichenfolgen im Ein-Buchstaben-Format (z. B. F, G, N) direkt.
Zum Beispiel num.ToString("F2")werden immer 2 Dezimalstellen wie angezeigt 123.40.

Sie müssen 0.##Muster verwenden , auch wenn es ein wenig ausführlich aussieht.

Ein vollständiges Codebeispiel:

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
quelle
7
Aber er will 123,40, nicht 123,4.
Andrew
8
Diese Frage nicht lösen, sondern meine lösen. Ich stimme dem zu, damit alle anderen es sehen können.
Emad
46

Alte Frage, aber ich wollte meiner Meinung nach die einfachste Option hinzufügen.

Ohne Tausende Trennzeichen:

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

Mit Tausenden von Trennzeichen:

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

Das gleiche, aber mit 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

Wenn Sie es an vielen Stellen benötigen , würde ich diese Logik in einer Erweiterungsmethode verwenden :

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

Versuchen

double myPrice = 123.0;

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

Ich weiß sowieso nicht, ob ich eine Bedingung in den Formatbezeichner einfügen soll, aber Sie können Ihren eigenen Formatierer schreiben:

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
quelle
6

Hier ist eine Alternative zu Uwe Keims Methode, die immer noch denselben Methodenaufruf beibehalten würde:

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

Mit MyCustomFormatso etwas wie:

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
quelle
Dies hat bei mir nicht funktioniert, da TrimEnd anscheinend eine Reihe von Zeichen wie {',', '.', ''} Anstelle
user1069816
Du hast recht - nicht sicher, wie ich das verpasst habe. Ich habe aktualisiert, um richtig zu funktionieren.
Steve
5
Abhängig vom aktuellen Thread ist das CurrentCultureDezimaltrennzeichen möglicherweise nicht vorhanden .. Wenn nicht CultureInfo.InvariantCulturemit verwendet wird string.Format, müssten Sie den Wert von überprüfen CultureInfo.NumberFormat.NumberDecimalSeparator, was ziemlich unelegant ist.
Groo
6

Einfacher einzeiliger Code:

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}
Philip Stuyck
quelle
Das Problem dabei ist, wenn es ausgeführt wird, wobei das Dezimaltrennzeichen ein Komma ist. Überprüfen Sie die Kommentare für diese Antwort .
Andrew
6

Wenn Ihr Programm schnell ausgeführt werden muss, rufen Sie value.ToString (formatString) auf, um eine um ~ 35% schnellere Zeichenfolgenformatierungsleistung im Vergleich zu $ ​​"{value: formatString}" und string.Format (formatString, value) zu erzielen.

Daten

Formatierungsleistung für C # -Strings - VS2017 15.4.5

Code

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

Code-Ausgabe

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

Verweise

Benutzerdefinierte Zeichenfolgen im numerischen Format [docs.microsoft.com]

Qt Charts BarChart Beispiel [doc.qt.io]

Neil Justice
quelle
5

Ich fürchte, es gibt kein eingebautes Format, das dies ermöglicht. Sie müssen ein anderes Format verwenden, je nachdem, ob der Wert eine ganze Zahl ist oder nicht. Oder formatieren Sie immer mit 2 Dezimalstellen und bearbeiten Sie die Zeichenfolge anschließend, um alle nachgestellten ".00" zu entfernen.

Nikki Locke
quelle
4

Wenn keine der anderen Antworten für Sie funktioniert, liegt dies möglicherweise daran, dass Sie das ContentPropertySteuerelement in der OnLoadFunktion binden. Dies bedeutet, dass dies nicht funktioniert:

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

Die Lösung ist einfach: Es gibt eine ContentStringFormatEigenschaft in der xaml. Wenn Sie das Etikett erstellen, gehen Sie wie folgt vor:

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

Oder

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

so etwas wird auch funktionieren:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")
ekkis
quelle
Das gibt ein Prozent?
3

Versuchen:

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

Um den Code, den Kahia geschrieben hat, klarer zu machen (es ist klar, wird aber schwierig, wenn Sie mehr Text hinzufügen möchten) ... versuchen Sie diese einfache Lösung.

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

Ich musste die zusätzliche Umwandlung (dezimal) hinzufügen, damit Math.Round die beiden dezimalen Variablen vergleichen konnte.

coding_is_fun
quelle
1

Das hat bei mir funktioniert!

String amount= "123.0000";
String.Format("{0:0.##}", amount);      // "123.00"
Edwin Ikechukwu Okonkwo
quelle
1
Das geht nicht Er möchte, dass 123.00 als "123" und 123.50 als "123.50" angezeigt werden.
Andrew
1

Wenn Sie mit Dezimalstellen aus einer (T-) SQL-Datenbank arbeiten, möchten Sie in der Lage sein, nullbare und nicht nullbare Dezimalstellen mit x Dezimalstellen zu konvertieren und den Code einfach anhand Ihrer Tabellendefinitionen zu überprüfen - und natürlich die anzuzeigen richtige Anzahl von Dezimalstellen für den Benutzer.

Leider konvertiert das Entity Framework so etwas wie SQL nicht automatisch decimal(18,2) in ein .NET-Äquivalent mit der gleichen Anzahl von Dezimalstellen (da nur Dezimalstellen mit voller Genauigkeit verfügbar sind). Sie müssen die Dezimalstellen manuell abschneiden.

Also habe ich es so gemacht:

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

Anwendungsbeispiel:

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)
}
Matt
quelle