使用自定义组和小数分隔符将数字格式化为字符串而不更改精度
Format number to string with custom group and decimal separator without changing precision
我想在 C# 中使用自定义 group/thousands 分隔符和小数点分隔符将一些数字格式化为字符串。组和小数分隔符可以根据用户输入进行更改,因此我想使用 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"
编辑:
是一种使用内置ToString()
的解决方法(通过使用数字占位符#
)和 Replace
and/orTrim
:
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 位有效数字的数字。
现在,将这两件事放在一起我们在这里进退两难!您希望程序执行的操作是:"Show my as many number of significant digits as it needs to be"。但是,当您输入 double n = 1234.5
时,程序会显示 1234.499999999999998
!但另一方面,您也不想固定小数点后的数字。
所以,我猜你应该使用 LINQ SkipWhile
和 Reverse
来做到这一点,而不是简单的内置。
下面是我作为扩展方法想出的解决方案。
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);
}
//这是最适合你的方法:
s3 = n3.ToString($"#####0{CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator}00");
//或者我的偏好:
s3 = n3.ToString($"###{CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator}##0{CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator}00");
//我一直在用这个。不。这是最好和最小的方法。 :)
//最好的祝福。埃尔辛·凯西斯。
您可以增加 NumberFormatInfo 中的小数位数并使用 TrimEnd() 删除额外的零和分隔符。
nfi.NumberDecimalDigits = 15;
public static string FormatDouble(double d, NumberFormatInfo nfi)
{
return d.ToString("N", nfi).TrimEnd('0', ' ', ',', '.');
}
我想在 C# 中使用自定义 group/thousands 分隔符和小数点分隔符将一些数字格式化为字符串。组和小数分隔符可以根据用户输入进行更改,因此我想使用 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"
编辑:
是一种使用内置ToString()
的解决方法(通过使用数字占位符#
)和 Replace
and/orTrim
:
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 位有效数字的数字。
现在,将这两件事放在一起我们在这里进退两难!您希望程序执行的操作是:"Show my as many number of significant digits as it needs to be"。但是,当您输入 double n = 1234.5
时,程序会显示 1234.499999999999998
!但另一方面,您也不想固定小数点后的数字。
所以,我猜你应该使用 LINQ SkipWhile
和 Reverse
来做到这一点,而不是简单的内置。
下面是我作为扩展方法想出的解决方案。
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);
}
//这是最适合你的方法:
s3 = n3.ToString($"#####0{CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator}00");
//或者我的偏好:
s3 = n3.ToString($"###{CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator}##0{CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator}00");
//我一直在用这个。不。这是最好和最小的方法。 :) //最好的祝福。埃尔辛·凯西斯。
您可以增加 NumberFormatInfo 中的小数位数并使用 TrimEnd() 删除额外的零和分隔符。
nfi.NumberDecimalDigits = 15;
public static string FormatDouble(double d, NumberFormatInfo nfi)
{
return d.ToString("N", nfi).TrimEnd('0', ' ', ',', '.');
}