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

Ian*_*oyd 6 .net c# globalization localization

考虑一个Decimal值:

Decimal value = -1234567890.1234789012M;
Run Code Online (Sandbox Code Playgroud)

我想将此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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

如何将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
Run Code Online (Sandbox Code Playgroud)

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

public override string ToString()
{
    return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
}
Run Code Online (Sandbox Code Playgroud)

除了Number.FormatDecimal隐藏在某处:

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

所以这是一个死胡同.

小智 7

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

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

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

var culture = CultureInfo.CreateSpecificCulture("fr-CH");
Decimal value = -1234567890.1234789012M;

Console.WriteLine(value.ToString("##,#.###############", culture.NumberFormat));
Run Code Online (Sandbox Code Playgroud)

会输出

 -1'234'567'890.1234789012
Run Code Online (Sandbox Code Playgroud)

编辑#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));
}
Run Code Online (Sandbox Code Playgroud)

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

--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
Run Code Online (Sandbox Code Playgroud)

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

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

要显式控制要输出的小数位数,可以克隆区域性提供的数字格式并修改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));
Run Code Online (Sandbox Code Playgroud)

这输出:

-1'234'567'890.123478901200000000000000000000
Run Code Online (Sandbox Code Playgroud)


Eri*_*SFT 5

您可以指定自定义模式(该模式将适当地解析为特定于文化的分组方法以及适当的分组和小数分隔符字符)。模式可以有正、负和零部分。正模式始终相同,但负模式取决于区域性,可以从 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

样本输出

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
Run Code Online (Sandbox Code Playgroud)

当前没有使用NegativeNumberFormat4 ( n -) 的语言环境,因此无法测试这种情况。但没有理由认为它会失败。