Використовуючи 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.