Uso del formato de cadena para mostrar decimales de hasta 2 lugares o un entero simple

291

Tengo un campo de precio para mostrar que a veces puede ser 100 o 100.99 o 100.9, lo que quiero es mostrar el precio en 2 decimales solo si los decimales se ingresan para ese precio, por ejemplo, si es 100, por lo que solo debería muestre 100 no 100.00 y si el precio es 100.2, debería mostrar 100.20 de manera similar para 100.22 debería ser el mismo. Busqué en Google y encontré algunos ejemplos, pero no coincidían exactamente con lo que quería:

// 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"
Señor a
fuente
44
posible duplicado del formato .net decimal a dos lugares o un número entero
Binary Worrier
1
RE: "Lo que quiero es mostrar el precio en 2 decimales solo si se ingresan los decimales para ese precio", por lo que si el usuario escribe "100.00", desea mostrar "100.00", pero si escribe "100" solo quieres mostrar "100"? - los tipos de números solo rastrean el valor del número, no cuáles de los dígitos insignificantes fueron ingresados ​​por un usuario y cuáles no, para eso necesitará usar una cadena.
BrainSlugs83
2
@BinaryWorrier Creo que esta pregunta puede ser un duplicado, pero tiene respuestas mucho mejores y más completas. OMI, el otro debe marcarse como un duplicado de este.
Ryan Gates
1
simplemente agregue .Replace (". 00", "")
Dave Sumter

Respuestas:

156

Una forma poco elegante sería:

var my = DoFormat(123.0);

Con DoFormatser algo como:

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

No es elegante pero funciona para mí en situaciones similares en algunos proyectos.

Uwe Keim
fuente
66
Esta no es realmente la pregunta que se hizo, pero lo había sido, ¿por qué no usar string.Format ("{0: 0.00}"). Reemplazar (". 00", "")?
BrainSlugs83
18
@ BrainSlugs83: dependiendo del hilo actual CurrentCulture, el separador decimal puede no ser. . A menos que CultureInfo.InvariantCulturese use con string.Format, tendría que verificar el valor de CultureInfo.NumberFormat.NumberDecimalSeparator, y eso sería una verdadera PITA. :)
Groo
@Uwe Keim ¿Qué pasa si tengo 60000int y quiero que sea60.000 ?
Prashant Pimpale
Esta respuesta es un caso de "reinventar una rueda cuadrada". No tiene en cuenta la cultura o el hecho de que esto ya ha sido manejado por .NET.
bytedev
523

Perdón por reactivar esta pregunta, pero no encontré la respuesta correcta aquí.

Al formatear números, puede usarlo 0como un lugar obligatorio y #como un lugar opcional.

Entonces:

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

También puedes combinar 0con #.

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"

Para este método de formateo siempre se utiliza CurrentCulture. Para algunas culturas .se cambiará a ,.

Respuesta a la pregunta original:

La solución más simple proviene de @Andrew ( aquí ). Así que personalmente usaría algo como esto:

var number = 123.46;
String.Format(number % 1 == 0 ? "{0:0}" : "{0:0.00}", number)
Gh61
fuente
20
Al principio, pensé que esta debería ser la respuesta, hasta que volví a leer la pregunta original varias veces. El OP no tiene del todo claro qué es exactamente lo que quiere, pero parece que siempre quiere 2 decimales si alguien ingresa una fracción. Entonces, si alguien ingresó 1.1, entonces querría 1.10; Este código no haría eso.
Doug S
40
Vaya, lo leí de nuevo y tienes razón. Entonces, esta no es la respuesta correcta, pero al menos alguien puede encontrar esto útil.
Gh61
Lo que se necesita OP se puede lograr con esto: stackoverflow.com/a/33180829/2321042
Andrew
Lo encontré útil, y (de alguna manera) coincide con lo que hace un BoundField en un GridView con una instrucción SqlDouble y sin formato. Debes indicar el número máximo que mostrarás. (Vs. BoundField, feliz de mostrar tantos o tan pocos como quieras)
fortboise
Sí, esto fue útil, pero ¿cómo mostrar solo dos decimales si el decimal está presente? es decir, si es un entero, ¿no muestra decimales?
Nigel Fds
64

Este es un caso de uso de número flotante de formato común.

Desafortunadamente, todas las cadenas de formato de una letra incorporadas (por ejemplo, F, G, N) no lograrán esto directamente.
Por ejemplo, num.ToString("F2")siempre mostrará 2 decimales como 123.40.

Tendrás que usar el 0.##patrón incluso si se ve un poco detallado.

Un ejemplo de código completo:

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
fuente
77
Pero él quiere 123.40, no 123.4.
Andrew
8
No resolviendo esta pregunta sino resolviendo la mía. Voto esto para que todos lo vean.
Emad
46

Antigua pregunta pero quería agregar la opción más simple en mi opinión.

Sin miles de separadores:

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

Con miles de separadores:

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

Lo mismo pero con 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 lo necesita en muchos lugares , usaría esta lógica en un método de extensión :

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

tratar

double myPrice = 123.0;

String.Format(((Math.Round(myPrice) == myPrice) ? "{0:0}" : "{0:0.00}"), myPrice);
Yahia
fuente
55
string.Format ((número% 1) == 0? "{0: 0}": "{0: 0.00}", número);
Patrick
8

No sé de ninguna manera poner una condición en el especificador de formato, pero puede escribir su propio formateador:

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

Aquí hay una alternativa al método de Uwe Keim, que aún mantendría la misma llamada al método:

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

Con MyCustomFormatser algo como:

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
fuente
Esto no funcionó para mí, ya que parece que TrimEnd toma una serie de caracteres como {',', '.', ''} En lugar de una cadena como ".00" - Ver msdn.microsoft.com/en-us/ library /
system.string.trimend.aspx
Tienes razón, no estoy seguro de cómo me perdí eso. He actualizado para que funcione correctamente.
Steve
55
Dependiendo de los hilos actuales CurrentCulture, el separador decimal puede no serlo .. A menos que CultureInfo.InvariantCulturese use con string.Format, tendría que verificar el valor de CultureInfo.NumberFormat.NumberDecimalSeparator, que es bastante poco elegante.
Groo
6

Código simple de una línea:

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}
Philip Stuyck
fuente
El problema con esto es si se ejecuta donde el separador decimal es una coma. Revise los comentarios para esta respuesta .
Andrew
6

Si su programa necesita ejecutarse rápidamente, llame a value.ToString (formatString) para obtener un rendimiento de formateo de cadenas ~ 35% más rápido en relación con $ "{value: formatString}" y string.Format (formatString, value).

Datos

Rendimiento de formato de cadena C # - VS2017 15.4.5

Código

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ódigo de salida

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

Referencias

Cadenas de formato numérico personalizado [docs.microsoft.com]

Gráficos Qt Ejemplo de gráfico de barras [doc.qt.io]

Neil Justice
fuente
5

Me temo que no hay un formato integrado que haga esto. Tendrá que usar un formato diferente dependiendo de si el valor es un número entero o no. O siempre formatee a 2 decimales y manipule la cadena después para eliminar cualquier ".00" final.

Nikki Locke
fuente
4

Si ninguna de las otras respuestas funciona para usted, puede deberse a que está vinculando ContentPropertyun control en la OnLoadfunción, lo que significa que esto no funcionará:

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

La solución es simple: hay una ContentStringFormatpropiedad en el xaml. Entonces, cuando cree la etiqueta, haga esto:

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

O

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

algo como esto también funcionará:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")
ekkis
fuente
Eso da un porcentaje?
3

Tratar:

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

Para que el código sea más claro que Kahia escribió (es claro pero se vuelve complicado cuando quieres agregarle más texto) ... prueba esta solución 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);

Tuve que agregar el elenco adicional (decimal) para que Math.Round compare las dos variables decimales.

coding_is_fun
fuente
1

¡Esto funcionó para mí!

String amount= "123.0000";
String.Format("{0:0.##}", amount);      // "123.00"
Edwin Ikechukwu Okonkwo
fuente
1
Eso no funciona Quiere que 123.00 se muestre como "123" y 123.50 como "123.50".
Andrew
1

Cuando se trata de decimales que provienen de una base de datos SQL (T-), desea poder convertir decimales anulables y no anulables con x decimales y poder revisar el código fácilmente contra las definiciones de su tabla y, por supuesto, mostrar el número correcto de decimales para el usuario.

Desafortunadamente, Entity Framework no convierte automáticamente algo así como un SQL decimal(18,2)en un equivalente .NET con el mismo número de lugares decimales (ya que solo hay un decimal con total precisión disponible). Tienes que truncar los lugares decimales manualmente.

Entonces, lo hice de esta manera:

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

Ejemplo de uso:

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)
}
Mate
fuente