2016-04-19 2 views
2

Я хотел бы отформатировать некоторые номера строк в C# с помощью специализированного разделителя групп/тысяч и десятичного разделителя. Групповой и десятичный разделитель могут меняться в зависимости от пользовательского ввода, поэтому я хотел бы использовать объект NumberFormatInfo вместо стробированной строки форматирования. Мой код ниже получает правильные разделители, но он меняет точность числа, чтобы всегда быть двумя десятичными знаками, тогда как я хочу сохранить полную точность числа и показывать только десятичные места, когда это необходимо (поэтому целочисленные значения не имеют десятичных знаков) ,Номер формата для строки с настраиваемым разделителем групп и десятичных знаков без изменения точности

Как я могу это достичь? Я предполагаю, что мне нужно изменить параметр «N», но изменить его на что?

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 

var nfi = new NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
nfi.NumberGroupSeparator = " "; 

string s1 = n1.ToString("N", nfi); //want "1 234" but I get "1 234,00" 
string s2 = n2.ToString("N", nfi); //want "1 234,5" but I get "1 234,50" 
string s3 = n3.ToString("N", nfi); //correct output of "1 234 567,89" 
string s4 = n4.ToString("N", nfi); //want " 1 234,567" but I get "1 234,57" 

ответ

3

Ниже приведено решение, которое я разработал как метод расширения.

public static string Format(this double d, NumberFormatInfo numberFormatInfo) 
{ 
    string s = d.ToString(CultureInfo.InvariantCulture); 
    int index = s.IndexOf('.'); 
    int decimalPlaces = index == -1 ? 0 : s.Length - index - 1; 
    return d.ToString($"N{decimalPlaces}", numberFormatInfo); 
} 
+0

Вы пробовали мое решение, используя 'Replace' и' Trim' или 'LINQ'? Все они встроены, если вы ищете встроенные решения ... – Ian

+0

Ваше решение не удастся при многих обстоятельствах, поскольку вы предоставляете «### ### ###. ###» в качестве параметра и этой строки зависит от значения double и количества цифр десятичной запятой, которое оно имеет. Оно также зависит от разделителя десятичных чисел и разделителя групп в объекте NumberFormatInfo. Например, ваше решение завершится неудачно с двойным значением 0.1234, когда оно округляет его до три знака после запятой. Создание пользовательской версии этой строки для каждого номера и объекта NumberFormatInfo является склонным к ошибкам и нецелесообразным. Мое решение всегда работает с любым двойным и любым объектом NumberFormatInfo – tjsmith

+0

, который я вижу ... тогда вы можете также использовать LINK , так как он является встроенным. Решение LINQ должно иметь возможность обрабатывать другие упоминаемые вами решения. – Ian

0

Edit:

Там есть обходной путь с помощью встроенного в ToString() (с помощью цифр заполнитель #) иReplaceи/илиTrim:

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 
string s1 = n1.ToString("### ### ###.###").Replace(".",",").Trim(); 
string s2 = n2.ToString("### ### ###.###").Replace(".", ",").Trim(); 
string s3 = n3.ToString("### ### ###.###").Replace(".", ",").Trim(); 
string s4 = n4.ToString("### ### ###.###").Replace(".", ",").Trim(); 

Комбинат ИНГ его числовом формате для чтения , в качестве десятичного разделителя не работы, хотя:

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 

var nfi = new NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
nfi.NumberGroupSeparator = " "; 

string s1 = n1.ToString("### ### ###,###", nfi); //doesn't work 
string s2 = n2.ToString("### ### ###,###", nfi); 
string s3 = n3.ToString("### ### ###,###", nfi); 
string s4 = n4.ToString("### ### ###,###", nfi); 

Оригинал:

Я думаю, вы не можете использовать только встроенный ToString(), чтобы получить его правильно. Вы, вероятно, потребуются некоторые LINQ уловки, чтобы получить результат, который вы хотите:

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 

var nfi = new NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
nfi.NumberGroupSeparator = " "; 

string s1 = new string(n1.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
string s2 = new string(n2.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
string s3 = new string(n3.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
string s4 = new string(n4.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 

Там причина из-за двух вещей следующим образом:

  1. Первый, double является не точным. Когда вы вводите что-то вроде double n = 1234.5, фактическое double значение, хранящееся может быть что-то вроде n = 1234.499999999999998

  2. Во-вторых, речь идет о ToString(). Он действительно используется только для форматирования. Другими словами, зависит от того, как вы его диктуете, это покажет что-то. Например, если вы даете инструкцию, чтобы показать номер с 2 значащими цифрами после десятичного разделителя, тогда он будет показывать число с ровно 2 значащими цифрами после десятичного разделителя.

Теперь, положив две вещи вместе мы получили дилемму здесь! То, что вы хотите, чтобы программа сделала, это: «Покажите мне столько же значительных цифр, сколько и должно быть». Однако, когда вы введете double n = 1234.5, программа покажет 1234.499999999999998! Но, с другой стороны, вы также не хотите фиксировать число после десятичного разделителя.

Итак, я думаю, вы должны использовать LINQ SkipWhile и Reverse, чтобы сделать это, а не простым встроенным.

Смежные вопросы