Utilisation du format de chaîne pour afficher une décimale jusqu'à 2 places ou un entier simple

291

J'ai un champ de prix à afficher qui peut parfois être 100 ou 100,99 ou 100,9, ce que je veux, c'est afficher le prix à 2 décimales uniquement si les décimales sont entrées pour ce prix, par exemple si c'est 100 donc il ne devrait afficher 100 et non 100,00 et si le prix est 100,2, il devrait afficher 100,20 de même pour 100,22 devrait être le même. J'ai googlé et j'ai trouvé quelques exemples mais ils ne correspondaient pas exactement à ce que je voulais:

// 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"
Mr A
la source
1
RE: "Ce que je veux, c'est afficher le prix en 2 décimales uniquement si les décimales sont entrées pour ce prix" - donc si l'utilisateur tape "100,00", vous voulez afficher "100,00", mais s'il tape "100" vous voulez seulement afficher "100"? - les types de numéros ne font que suivre la valeur du nombre - pas ceux des chiffres insignifiants qui ont été saisis par un utilisateur et ceux qui ne l'ont pas été - pour cela, vous devrez utiliser une chaîne.
BrainSlugs83
2
@BinaryWorrier Je pense que cette question peut être un doublon, mais elle a des réponses bien meilleures et plus complètes. OMI l'autre devrait être marqué comme un double de celui-ci.
Ryan Gates
1
il suffit d'ajouter .Replace (". 00", "")
Dave Sumter

Réponses:

156

Une manière inélégante serait:

var my = DoFormat(123.0);

Avec DoFormatêtre quelque chose comme:

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

Pas élégant mais travaillant pour moi dans des situations similaires dans certains projets.

Uwe Keim
la source
6
Ce n'est pas vraiment la question qui a été posée - mais l'avait été - pourquoi ne pas simplement utiliser string.Format ("{0: 0.00}"). Replace (". 00", "")?
BrainSlugs83
18
@ BrainSlugs83: selon le thread actuel CurrentCulture, le séparateur décimal peut ne pas l'être .. À moins qu'il ne CultureInfo.InvariantCulturesoit utilisé avec string.Format, vous devrez vérifier la valeur de CultureInfo.NumberFormat.NumberDecimalSeparator, et ce serait un vrai PITA. :)
Groo
@Uwe Keim Et si j'ai un 60000int et que je veux que ce soit 60.000?
Prashant Pimpale
Cette réponse est un cas de "réinvention d'une roue carrée". Ne prend pas en compte la culture ou le fait que cela a déjà été géré par .NET.
bytedev
523

Désolé d'avoir réactivé cette question, mais je n'ai pas trouvé la bonne réponse ici.

Dans la mise en forme des nombres, vous pouvez utiliser 0comme emplacement obligatoire et #comme emplacement facultatif.

Alors:

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

Vous pouvez également combiner 0avec #.

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"

Pour cette méthode de formatage est toujours utilisée CurrentCulture. Pour certaines cultures .sera changé en ,.

Réponse à la question d'origine:

La solution la plus simple vient de @Andrew ( ici ). Donc, personnellement, j'utiliserais quelque chose comme ceci:

var number = 123.46;
String.Format(number % 1 == 0 ? "{0:0}" : "{0:0.00}", number)
Gh61
la source
20
Au début, je pensais que cela devrait être la réponse, jusqu'à ce que je relise la question d'origine plusieurs fois. L'OP ne sait pas exactement ce qu'il veut exactement, mais il semble qu'il veuille toujours 2 décimales si quelqu'un entre une fraction. Donc, si quelqu'un a entré 1.1 alors il voudrait 1.10; ce code ne ferait pas ça.
Doug S
40
Oups, je l'ai relu et vous avez raison. Donc, ce n'est pas la bonne réponse mais au moins quelqu'un pourrait trouver cela utile.
Gh61
Quel OP nécessaire peut être atteint avec ceci: stackoverflow.com/a/33180829/2321042
Andrew
Je viens de le trouver utile, et (quelque peu) correspondant à ce qu'un BoundField dans un GridView fait avec un SqlDouble et aucune instruction de format. Vous devez indiquer le nombre maximum que vous afficherez. (Vs. BoundField, heureux d'en montrer autant ou aussi peu que vous le souhaitez)
fortboise
Ouais c'était utile, mais comment montrer seulement deux décimales si la décimale est présente? c'est-à-dire si c'est un entier, alors ne pas afficher les décimales?
Nigel Fds
64

Il s'agit d'un cas d'utilisation de format flottant courant.

Malheureusement, toutes les chaînes de format à une lettre intégrées (par exemple, F, G, N) n'y parviendront pas directement.
Par exemple, num.ToString("F2")affichera toujours 2 décimales comme 123.40.

Vous devrez utiliser le 0.##motif même s'il a l'air un peu bavard.

Un exemple de code complet:

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
la source
7
Mais il veut 123,40, pas 123,4.
Andrew
8
Pas résoudre cette question mais résoudre la mienne. Je vote favorablement pour que tout le monde puisse le voir.
Emad
46

Vieille question mais je voulais ajouter l'option la plus simple à mon avis.

Sans séparateurs de milliers:

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

Avec des milliers de séparateurs:

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

La même chose mais avec 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

Si vous en avez besoin à de nombreux endroits , j'utiliserais cette logique dans une méthode d'extension :

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

essayer

double myPrice = 123.0;

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

Je ne sais pas de toute façon mettre une condition dans le spécificateur de format, mais vous pouvez écrire votre propre formateur:

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
la source
6

Voici une alternative à la méthode d'Uwe Keim, qui conserverait toujours le même appel de méthode:

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

Avec MyCustomFormatêtre quelque chose comme:

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
la source
Cela n'a pas fonctionné pour moi car il semble que TrimEnd accepte un tableau de caractères comme {',', '.', ''} Plutôt qu'une chaîne comme ".00" - Voir msdn.microsoft.com/en-us/ library / system.string.trimend.aspx
user1069816
Vous avez raison - je ne sais pas comment j'ai raté ça. J'ai mis à jour pour fonctionner correctement.
Steve
5
Selon le thread actuel CurrentCulture, le séparateur décimal peut ne pas l'être .. Sauf si CultureInfo.InvariantCultureest utilisé avec string.Format, vous devrez vérifier la valeur de CultureInfo.NumberFormat.NumberDecimalSeparator, ce qui est plutôt inélégant.
Groo
6

Code simple sur une ligne:

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}
Philip Stuyck
la source
Le problème avec ceci est s'il est exécuté où le séparateur décimal est une virgule. Vérifiez les commentaires pour cette réponse .
Andrew
6

Si votre programme doit s'exécuter rapidement, appelez value.ToString (formatString) pour des performances de formatage de chaîne ~ 35% plus rapides par rapport à $ "{value: formatString}" et string.Format (formatString, value).

Les données

Performances de formatage des chaînes C # - 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;
   }
}

Sortie de code

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

Références

Chaînes de format numérique personnalisées [docs.microsoft.com]

Exemple de diagramme à barres Qt Charts [doc.qt.io]

Neil Justice
la source
5

Je crains qu'il n'y ait pas de format intégré qui puisse faire cela. Vous devrez utiliser un format différent selon que la valeur est un nombre entier ou non. Ou toujours formatez à 2 décimales et manipulez ensuite la chaîne pour supprimer tout ".00" de fin.

Nikki Locke
la source
4

Si aucune des autres réponses ne fonctionne pour vous, c'est peut-être parce que vous liez ContentPropertyun contrôle dans la OnLoadfonction, ce qui signifie que cela ne fonctionnera pas:

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

La solution est simple: il y a une ContentStringFormatpropriété dans le xaml. Donc, lorsque vous créez l'étiquette, procédez comme suit:

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

Ou

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

quelque chose comme ça fonctionnera aussi:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")
ekkis
la source
Cela donne un pour cent?
3

Essayer:

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

Pour rendre le code plus clair que Kahia a écrit (il est clair mais devient difficile lorsque vous souhaitez y ajouter plus de texte) ... essayez cette solution simple.

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

J'ai dû ajouter la distribution supplémentaire (décimale) pour que Math.Round compare les deux variables décimales.

coding_is_fun
la source
1

Cela a fonctionné pour moi!

String amount= "123.0000";
String.Format("{0:0.##}", amount);      // "123.00"
Edwin Ikechukwu Okonkwo
la source
1
Ça ne marche pas. Il veut que 123,00 soit affiché comme "123" et 123,50 comme "123,50".
Andrew
1

Lorsque vous traitez avec des décimales provenant d'une base de données (T-) SQL, vous voulez pouvoir convertir les décimales nullables et non nullables avec x décimales et être en mesure de revoir le code facilement par rapport à vos définitions de table - et bien sûr, afficher le bon nombre de décimales pour l'utilisateur.

Malheureusement, Entity Framework ne convertit pas automatiquement quelque chose comme un SQL decimal(18,2)en équivalent .NET avec le même nombre de décimales (car il n'y a que des décimales avec une précision complète disponibles). Vous devez tronquer manuellement les décimales.

Donc, je l'ai fait de cette façon:

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

Exemple d'utilisation:

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
la source