十进制与千位分隔符串联?

考虑一个Decimal值:

 Decimal value = -1234567890.1234789012M; 

我想将此Decimal值转换为字符串,并包含“千位分隔符”

注意:我不想包括千位分隔符 ,我想包括数字分组 。 对于没有将数字分组为数千的文化,或者不使用逗号分隔组,差异很重要

在我的计算机上使用我当前的语言环境输出具有不同标准格式字符串的示例:

 value.ToString() = -1234567890..1234789012 (Implicit General) value.ToString("g") = -1234567890..1234789012 (General) value.ToString("d") = FormatException (Decimal whole number) value.ToString("e") = -1..234568e++009 (Scientific) value.ToString("f") = -1234567890..123 (Fixed Point) value.ToString("n") = -12,,3456,,7890..123 (Number with commas for thousands) value.ToString("r") = FormatException (Round trippable) value.ToString("c") = -$$12,,3456,,7890..123 (Currency) value.ToString("#,0.#") = -12,,3456,,7890..1 

想要的 (取决于文化)是:

 en-US -1,234,567,890.1234789012 ca-ES -1.234.567.890,1234789012 gsw-FR -1 234 567 890,1234789012 (12/1/2012: fixed gws-FR to gsw-FR) fr-CH -1'234'567'890.1234789012 ar-DZ 1,234,567,890.1234789012- prs-AF 1.234.567.890,1234789012- ps-AF 1،234،567،890,1234789012- as-IN -1,23,45,67,890.1234789012 lo-LA (1234567,890.1234789012) (some debate if numbers should be "1,234,567,890") qps-PLOC 12,,3456,,7890..1234789012 

如何将Decimal转换为字符串,使用数字分组?


更新 :一些更理想的输出,使用我目前的文化:

 -1234567890M --> -12,,3456,,7890 -1234567890.1M --> -12,,3456,,7890..1 -1234567890.12M --> -12,,3456,,7890..12 -1234567890.123M --> -12,,3456,,7890..123 -1234567890.1234M --> -12,,3456,,7890..1234 -1234567890.12347M --> -12,,3456,,7890..12347 -1234567890.123478M --> -12,,3456,,7890..123478 -1234567890.1234789M --> -12,,3456,,7890..1234789 -1234567890.12347890M --> -12,,3456,,7890..1234789 -1234567890.123478901M --> -12,,3456,,7890..123478901 -1234567890.1234789012M --> -12,,3456,,7890..1234789012 

更新 :我试图窥视Decimal.ToString()如何设法使用常规格式显示它需要显示的所有数字:

 public override string ToString() { return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo); } 

除了Number.FormatDecimal隐藏在某处:

 [MethodImpl(MethodImplOptions.InternalCall)] public static extern string FormatDecimal(decimal value, string format, NumberFormatInfo info); 

所以这是一个死胡同。

您可以指定自定义模式(模式将适当地解析为特定于区域性的分组方法以及相应的分组和小数分隔符字符)。 模式可以具有正,负和零部分 。 正模式总是相同,但负模式取决于文化,可以从NumberFormatInfo的NumberNegativePattern属性中检索。 由于您需要尽可能多的精度,您需要在小数点后填写28位数的占位符; 逗号力量分组。

  public static class DecimalFormatters { public static string ToStringNoTruncation(this Decimal n, IFormatProvider format) { NumberFormatInfo nfi = NumberFormatInfo.GetInstance(format); string[] numberNegativePatterns = { "(#,0.############################)", //0: (n) "-#,0.############################", //1: -n "- #,0.############################", //2: - n "#,0.############################-", //3: n- "#,0.############################ -"};//4: n - var pattern = "#,0.############################;" + numberNegativePatterns[nfi.NumberNegativePattern]; return n.ToString(pattern, format); } public static string ToStringNoTruncation(this Decimal n) { return n.ToStringNoTruncation(CultureInfo.CurrentCulture); } } 

样本输出

 Locale Output ======== ============================ en-US -1,234,567,890.1234789012 ca-ES -1.234.567.890,1234789012 hr-HR - 1.234.567.890,1234789012 gsw-FR -1 234 567 890,1234789012 fr-CH -1'234'567'890.1234789012 ar-DZ 1,234,567,890.1234789012- prs-AF 1.234.567.890,1234789012- ps-AF 1،234،567،890,1234789012- as-IN -1,23,45,67,890.1234789012 lo-LA (1234567,890.1234789012) qps-PLOC -12,,3456,,7890..1234789012 

目前没有使用NegativeNumberFormat 4( n - )的语言环境,因此无法测试该情况。 但是没有理由认为它会失败。

默认情况下,小数点上的ToString方法使用CultureInfo.CurrentCulture用于用户的会话,因此根据运行代码的对象而有所不同。

ToString方法还接受各种重载中的IFormatProvider。 这是您需要提供特定于文化的格式化程序的地方。

例如,如果您为fr-CH传递NumberFormat,则可以按文化期望格式化事物:

 var culture = CultureInfo.CreateSpecificCulture("fr-CH"); Decimal value = -1234567890.1234789012M; Console.WriteLine(value.ToString("##,#.###############", culture.NumberFormat)); 

会输出

  -1'234'567'890.1234789012 

编辑#3 – 使用自定义格式化程序重写。 这应该根据新的更新问题做你想做的事情。

编辑#4 – 完成所有输入,然后运行:

 public void TestOutput() { PrintValue(-1234567890M); PrintValue(-1234567890.1M); PrintValue(-1234567890.12M); PrintValue(-1234567890.123M); PrintValue(-1234567890.1234M); PrintValue(-1234567890.12347M); PrintValue(-1234567890.123478M); PrintValue(-1234567890.1234789M); PrintValue(-1234567890.12347890M); PrintValue(-1234567890.123478901M); PrintValue(-1234567890.1234789012M); } private static void PrintValue(decimal value) { var culture = CultureInfo.CreateSpecificCulture("qps-PLOC"); Console.WriteLine(value.ToString("##,#.###############", culture.NumberFormat)); } 

提供与您提供的输出匹配的输出:

 --12,,3456,,7890 --12,,3456,,7890..1 --12,,3456,,7890..12 --12,,3456,,7890..123 --12,,3456,,7890..1234 --12,,3456,,7890..12347 --12,,3456,,7890..123478 --12,,3456,,7890..1234789 --12,,3456,,7890..1234789 --12,,3456,,7890..123478901 --12,,3456,,7890..1234789012 

正如约书亚所指出的,这只适用于某些地区。

从它的外观来看,你需要选择两个邪恶中较小的一个:了解你的数字的精确度,或指定每种文化的格式。 我打赌知道你的数字的精确度可能会更容易。 在这种情况下,我的答案的先前版本可能是有用的:

要显式控制要输出的小数位数,可以克隆区域性提供的数字格式并修改NumberDecimalDigits属性。

 var culture = CultureInfo.CreateSpecificCulture("fr-CH"); Decimal value = -1234567890.1234789012M; NumberFormatInfo format = (NumberFormatInfo)culture.NumberFormat.Clone(); format.NumberDecimalDigits = 30; Console.WriteLine(value.ToString("n", format)); 

这输出:

 -1'234'567'890.123478901200000000000000000000 

在格式化字符串时,您需要包含文化。 您可以使用String.Format并将culture作为第一个参数包含在内,或者使用对象的ToString方法并使用带有文化的重载。

以下代码生成预期输出(gws-FR除外,它无法找到具有该字符串的文化)。

 namespace CultureFormatting { using System; using System.Globalization; class Program { public static void Main() { Decimal value = -1234567890.1234789012M; Print("en-US", value); Print("ca-ES", value); //print("gws-FR", value); Print("fr-CH", value); Print("ar-DZ", value); Print("prs-AF", value); Print("ps-AF", value); Print("as-IN", value); Print("lo-LA", value); Print("qps-PLOC", value); } static void Print(string cultureName, Decimal value) { CultureInfo cultureInfo = new CultureInfo(cultureName); cultureInfo.NumberFormat.NumberDecimalDigits = 10; // Or, you could replace the {1:N} with {1:N10} to do the same // for just this string format call. string result = String.Format(cultureInfo, "{0,-8} {1:N}", cultureName, value); Console.WriteLine(result); } } } 

上面的代码产生以下输出:

 en-US -1,234,567,890.1234789012 ca-ES -1.234.567.890,1234789012 fr-CH -1'234'567'890.1234789012 ar-DZ 1,234,567,890.1234789012- prs-AF 1.234.567.890,1234789012- ps-AF 1،234،567،890,1234789012- as-IN -1,23,45,67,890.1234789012 lo-LA (1234567,890.1234789012) qps-PLOC --12,,3456,,7890..1234789012 

如果您正在使用multithreading系统(如ASP.Net),则可以更改线程的CurrentCulture属性。 更改线程的文化将允许所有关联的ToStringString.Format调用使用该文化。

更新

既然你想要显示所有的精度,你将需要做一些工作。 使用NumberFormat.NumberDecimalDigits将起作用,但如果值的精度较低,则数字将以尾随零输出。 如果您需要确保显示每个数字而没有任何额外的数字,您需要事先计算精度并在将其转换为字符串之前进行设置。 StackOverflow问题Calculate System.Decimal Precision and Scale可以帮助您确定小数的精度。