Как указать пользовательский разделитель тысяч в строках формата

Когда я пробую приведенный ниже код, я получаю вывод 2 084 001. Что здесь может быть не так? Разве моя строка формата не должна переопределять текущие настройки культуры?

decimal v = 2084000.7621m;
System.Console.WriteLine(v.ToString("#,###,###"));
System.Console.ReadLine();

Если я изменю код для использования ToString("#,###,###", CultureInfo.InvariantCulture), я получу ожидаемый результат, т. е. 2 084 001, но я не могу указать поставщика формата, когда задаю свойство DataFormatString в элементах управления с привязкой к данным.

ВНИМАНИЕ: При использовании экранированного литерального разделителя группы, как описано ниже в принятых и других ответах, используемый литеральный символ всегда выводится, даже если он не нужен, например. применение строки формата #\,###\,### к значению 324 приводит к выходному значению ,,324.


person ProfK    schedule 26.08.2011    source источник
comment
Какая локаль по умолчанию? Похоже, что по умолчанию ThousandsSeparator установлен на пробел.   -  person Oded    schedule 26.08.2011
comment
@Oded, это en-ZA, и у него есть пробел. Вот почему я использую явную строку формата, чтобы попытаться переопределить значение по умолчанию.   -  person ProfK    schedule 26.08.2011
comment
Я сделал название более явным для лучшей возможности восстановления, надеюсь, вы согласны.   -  person Stefan Steinegger    schedule 26.08.2011


Ответы (2)


Насколько я понимаю строки пользовательского числового формата, символ , предназначен для размещения разделителя групп в форматирование (и не указывать, какой символ использовать). Чтобы сделать его явным символом, вам нужно использовать escape-символ \.

v.ToString(@"#\,###\,###")

Недостатком этого является то, что строка формата зависит от размера числа. В этом случае вы всегда получите две запятые в результирующей строке, даже если число меньше или больше.

Чтобы переопределить разделитель групп, необходимо указать собственный NumberFormatInfo.

Получил этот тест работает:

decimal v = 2084000.7621m;

// clone the InvariantCulture to avoid specifying everything from scratch
var myNumberFormat = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
myNumberFormat.NumberGroupSeparator = "@";
myNumberFormat.NumberDecimalSeparator = "*";
Assert.AreEqual("2@084@000*7621", v.ToString("#,###,###.####", myNumberFormat));

На самом деле не имеет значения, где и сколько разделителей групп вы помещаете в строку формата. Вы также можете сделать это: "#,#.####" с точно таким же результатом. (Это преимущество использования символа-разделителя группы, в отличие от первого решения).

person Stefan Steinegger    schedule 26.08.2011
comment
Я, спасибо. Если бы только документация была немного более явной по этому поводу. На самом деле у меня была такая же проблема много лет назад, и в документах ничего не напоминало. Также кажется, что большинство ответов на форумах в других местах в Интернете не учитывают этого. - person ProfK; 26.08.2011

Ваша проблема в том, что символ , в вашей строке формата не означает «вставить запятую»; на самом деле это означает «вставить разделитель тысяч для текущей локали», который является пробелом в вашей локали по умолчанию.

Вам нужно будет избежать запятой, поставив перед ней обратную косую черту \ в строке формата. Возможно, вам придется использовать двойную обратную косую черту (или дословную строку), чтобы компилятор принял экранирование, как вы предполагали.

person Stuart Cook    schedule 26.08.2011