使用自定义组和小数分隔符将数字格式化为字符串而不更改精度

Posted

技术标签:

【中文标题】使用自定义组和小数分隔符将数字格式化为字符串而不更改精度【英文标题】:Format number to string with custom group and decimal separator without changing precision 【发布时间】:2016-04-19 02:56:59 【问题描述】:

我想在 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"

【问题讨论】:

【参考方案1】:

以下是我提出的扩展方法的解决方案。

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($"NdecimalPlaces", numberFormatInfo);

【讨论】:

您是否尝试过使用ReplaceTrimLINQ 的解决方案?如果您寻找内置解决方案,这些都是内置的...... 您的解决方案在许多情况下都会失败,因为您提供 ""### ### ###.###" 作为参数,并且该字符串取决于双精度值以及如何它有许多小数位。它还取决于 NumberFormatInfo 对象中的小数分隔符和组分隔符。例如,您的解决方案将失败,因为它会将其四舍五入到小数点后三位。创建一个自定义版本每个数字和 NumberFormatInfo 对象的字符串容易出错且不实用。我的解决方案始终适用于任何 double 和任何 NumberFormatInfo 对象 我明白了...那么您也可以考虑使用LINQ,因为它是内置的。 LINQ 解决方案应该能够处理您提到的其他解决方案。 无论如何,你得到了我对扩展的支持。 (尚未测试,但似乎还可以)。【参考方案2】:

编辑:

一种使用内置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());

原因有以下两点:

    首先,double精确的。当您输入double n = 1234.5 之类的内容时,实际存储的double 值可能类似于n = 1234.499999999999998

    其次,是关于ToString()。它实际上仅用于格式化。换句话说,取决于你如何口述它,它会显示出一些东西。例如,如果您指示在小数分隔符后显示 2 位有效数字,那么它将在小数分隔符后显示正好 2 位有效数字。

现在,把这两件事放在一起我们遇到了一个两难境地!您希望程序执行的操作是:“显示我所需的尽可能多的有效数字”。但是,当您输入double n = 1234.5 时,程序将显示1234.499999999999998!但另一方面,您也不想固定小数分隔符后的数字。

所以,我猜你应该使用 LINQ SkipWhileReverse 来做到这一点,而不是简单的内置。

【讨论】:

【参考方案3】:

//这是最适合你的方式:

s3 = n3.ToString($"### ##0CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator00");

//或者我更喜欢:

s3 = n3.ToString($"###CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator##0CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator00");

//我一直在用这个。没有。这是最好和最小的方式。 :) //最好的祝福。厄辛·凯西斯。

【讨论】:

【参考方案4】:

您可以增加 NumberFormatInfo 中的小数位数并使用 TrimEnd() 删除额外的零和分隔符。

    nfi.NumberDecimalDigits = 15;

    public static string FormatDouble(double d, NumberFormatInfo nfi)
    
        return d.ToString("N", nfi).TrimEnd('0', ' ', ',', '.');
    

【讨论】:

以上是关于使用自定义组和小数分隔符将数字格式化为字符串而不更改精度的主要内容,如果未能解决你的问题,请参考以下文章

ActionScript 3 将数字格式化为字符串 - 使用小数和千位分隔符

将数字格式化为字符串-带小数和千位分隔符

如何将数字格式化为一定数量的小数位加逗号分隔符?

DecimalFormat详解

自定义工具提示并将数字格式化为高图的小数点后 2 位

如何将双精度值格式化为点后两位小数且分隔符为千位的字符串?