Використовуючи String Format, щоб показати десятковий до 2-х місць або просте ціле число


291

У мене є поле цін для відображення, яке іноді може бути або 100, або 100,99, або 100,9, те, що я хочу, - це відображати ціну в двох десяткових знаках, тільки якщо децимальні знаки вводяться за цією ціною, наприклад, якщо її 100 так вона повинна бути лише покажіть 100 не 100,00, а якщо ціна 100,2, вона повинна відображати 100,20, аналогічно для 100,22 має бути однаковою. Я гуглив і натрапив на кілька прикладів, але вони не відповідали саме тому, що я хотів:

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

4
можливий
— повтор

1
RE: "Я хочу, щоб відобразити ціну в двох десяткових знаках, тільки якщо децимальні знаки введені за цією ціною" - так що якщо користувач вводить "100.00", ви хочете показати "100.00", але якщо вони набирають "100" ви хочете показати лише "100"? - типи чисел відстежують лише значення числа - не те, які з незначних цифр було введено користувачем, а які не - для цього вам потрібно буде використовувати рядок.
— BrainSlugs83

2
@BinaryWorrier Я думаю, що це питання може бути дублікатом, але в ньому є набагато кращі та повніші відповіді. IMO інший повинен бути позначений як дублікат цього.
— Райан Гейтс

1
просто додайте. Замініть (". 00", "")
— Дейв Самтер

Відповіді:


156

Неелегантним способом було б:

var my = DoFormat(123.0);

Маючи DoFormatщось подібне:

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

Не елегантно, але працює для мене в подібних ситуаціях в деяких проектах.


6
Це насправді не питання, яке було задано - але чи було це - чому б просто не використовувати string.Format ("{0: 0.00}"). Замінити (". 00", "")?
— BrainSlugs83

18
@ BrainSlugs83: залежно від поточної нитки CurrentCultureдесяткового роздільника може не бути .. Якщо CultureInfo.InvariantCultureце не використовується string.Format, вам доведеться перевірити значення CultureInfo.NumberFormat.NumberDecimalSeparator, і це був би справжній ПДФА. :)
— Groo

@Uwe Keim Що робити, якщо у мене є 60000Int, і я хочу, щоб це було 60.000?
— Прашант Пімпале

Ця відповідь є випадком "винахід квадратного колеса". Не враховує культуру чи той факт, що цим уже займався .NET.
— bytedev

523

Вибачте за повторну активацію цього питання, але я не знайшов правильної відповіді.

У форматуванні номерів ви можете використовувати 0як обов'язкове місце, так і #як необов'язкове місце.

Так:

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

Ви також можете комбінувати 0з #.

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"

Для цього завжди використовується метод формування CurrentCulture. Для деяких культур .буде змінено на ,.

Відповідь на оригінальне запитання:

Найпростіше рішення походить від @Andrew ( тут ). Тому я особисто використовував щось подібне:

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

20
Спочатку я вважав, що це має бути відповіддю, поки не перечитав оригінальне запитання кілька разів. ОП не зовсім зрозуміло, чого він саме хоче, але, здається, він завжди хоче 2 знаки після коми, якщо хтось вводить дріб. Тож якщо хтось ввів 1.1, він хотів би 1.10; цей код не зробив би цього.
— Doug S

40
На жаль, я прочитав його ще раз, і ти маєш рацію. Отже, це не правильна відповідь, але принаймні хтось може вважати це корисним.
— Gh61

Чого потрібно досягти завдяки цьому: stackoverflow.com/a/33180829/2321042
— Андрій

Щойно я вважаю корисним і (дещо) співпадаючим з тим, що BoundField у GridView робить із SqlDouble, а не інструкцією щодо форматування. Ви повинні вказати максимум #, який ви покажете. (Vs. BoundField, із задоволенням показую стільки або скільки завгодно)
— fortboise

Так, це було корисно, але як показати лише два десяткових знаки, якщо є десятковий знак? тобто якщо його ціле число, то не показуйте десяткові числа?
— Найджел Фдс

64

Це звичайний випадок використання плаваючого числа форматування.

На жаль, всі вбудовані однобуквенні рядки формату (наприклад, F, G, N) цього не досягнуть безпосередньо.
Наприклад, num.ToString("F2")завжди буде відображатися 2 знаки після коми 123.40.

Вам доведеться використовувати 0.##шаблон, навіть якщо це виглядає трохи багатослівним.

Повний приклад коду:

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
Але він хоче 123.40, а не 123.4.
— Андрій

8
Не вирішуючи це питання, а вирішуючи моє. Я підтримую це, щоб усі його побачили.
— Емад

46

Старе питання, але я хотів додати найпростіший варіант, на мою думку.

Без тисяч роздільників:

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

З тисячами роздільників:

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

Те саме, але зі 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

Якщо вам це потрібно в багатьох місцях , я використовую цю логіку в методі розширення :

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

28

спробуйте

double myPrice = 123.0;

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

5
string.Format ((число% 1) == 0? "{0: 0}": "{0: 0.00}", число);
— Патрік

8

Я не знаю ні в якому разі, щоб поставити умову в специфікатор формату, але ви можете написати свій власний формат:

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

Ось альтернатива методу Уве Кейма, який би все ще підтримував той самий виклик методу:

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

Маючи MyCustomFormatщось подібне:

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

Для мене це не спрацювало, оскільки, здається, TrimEnd займає масив символів на зразок {',', '.', ''}, А не рядок типу ".00" - Див. Msdn.microsoft.com/en-us/ library / system.string.trimend.aspx
— user1069816

Ти маєш рацію - не впевнений, як я це пропустив. Я оновив, щоб правильно працювати.
— Стів

5
Залежно від поточного потоку CurrentCulture, десятковий роздільник може бути .. Якщо CultureInfo.InvariantCultureце не використовується string.Format, вам доведеться перевірити значення CultureInfo.NumberFormat.NumberDecimalSeparator, яке є неелегантним.
— Гроо

6

Простий код рядка:

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

Проблема з цим полягає в тому, якщо він запускається там, де десятковим роздільником є ​​кома. Перевірте коментарі до цієї відповіді .
— Андрій

6

Якщо вашій програмі потрібно швидко запустити, виклик value.ToString (formatString) для ~ 35% швидшої продуктивності форматування рядків відносно $ "{value: formatString}" та string.Format (formatString, значення).

Дані

Ефективність форматування рядків C # - VS2017 15.4.5

Код

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# 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

Список літератури

Спеціальні рядки числового формату [docs.microsoft.com]

Приклад BarChart діаграм Qt [doc.qt.io]


5

Боюся, немає вбудованого формату, який би це зробив. Вам доведеться використовувати інший формат залежно від того, значення є цілим числом чи ні. Або завжди відформатуйте до 2 знаків після коми і маніпулюйте рядком після цього, щоб видалити будь-який пробіг ".00".


4

Якщо жоден з інших відповідей не працює для вас, це може бути тому, що ви прив'язуєте ContentPropertyелемент керування у OnLoadфункції, це означає, що це не буде працювати:

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

Рішення просте: ContentStringFormatу xaml є властивість. Тож коли ви створюєте мітку, зробіть це:

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

Або

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

3

щось подібне також буде працювати:

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

Це дає відсоток?


2

Щоб зробити код більш зрозумілим, про який писала Кахія (зрозуміло, але стає складніше, коли ви хочете додати в нього більше тексту) ... спробуйте це просте рішення.

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

Мені довелося додати додатковий склад (десятковий), щоб мати Math.Round порівняти дві десяткові змінні.



1

Маючи справу з десятковими знаками, що надходять із бази даних (T-) SQL, ви хочете мати змогу конвертувати нульові та нерегульовані десяткові знаки з десятковими знаками x та мати можливість легко переглядати код відповідно до визначень вашої таблиці - і, звичайно, показувати відображення потрібна кількість десяткових знаків для користувача.

На жаль, Entity Framework не автоматично перетворює щось на зразок SQL decimal(18,2)в еквівалент .NET з однаковою кількістю десяткових знаків (оскільки доступний лише десятковий з повною точністю). Ви повинні усікати десяткові знаки вручну.

Отже, я зробив це так:

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

Приклад використання:

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)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.