在C#中将double格式化为字符串

时间:2023-01-14 15:56:41

I have a Double which could have a value from around 0.000001 to 1,000,000,000.000

我有一个Double,其值可以从0.000001到1,000,000,000.000左右

I wish to format this number as a string but conditionally depending on its size. So if it's very small I want to format it with something like:

我希望将此数字格式化为字符串,但有条件地取决于其大小。因此,如果它非常小,我想用以下内容格式化它:

String.Format("{0:.000000000}", number);

if it's not that small, say 0.001 then I want to use something like

如果不是那么小,比如0.001,那么我想用类似的东西

String.Format("{0:.00000}", number);

and if it's over, say 1,000 then format it as:

如果它结束了,比如1000,然后将其格式化为:

String.Format("{0:.0}", number);

Is there a clever way to construct this format string based on the size of the value I'm going to format?

有没有一种聪明的方法来根据我要格式化的值的大小来构造这个格式字符串?

5 个解决方案

#1


15  

Use Math.Log10 of the absolute value of the double to figure out how many 0's you need either left (if positive) or right (if negative) of the decimal place. Choose the format string based on this value. You'll need handle zero values separately.

使用double的绝对值的Math.Log10来计算你需要多少0的小数位左边(如果是正数)或右边(如果是负数)。根据此值选择格式字符串。您需要单独处理零值。

string s;
double epislon = 0.0000001; // or however near zero you want to consider as zero
if (Math.Abs(value) < epislon) {
    int digits = Math.Log10( Math.Abs( value ));
    // if (digits >= 0) ++digits; // if you care about the exact number
    if (digits < -5) {
       s = string.Format( "{0:0.000000000}", value );
    }
    else if (digits < 0) {
       s = string.Format( "{0:0.00000})", value );
    }
    else {
       s = string.Format( "{0:#,###,###,##0.000}", value );
    }
}
else {
    s = "0";
}

Or construct it dynamically based on the number of digits.

或者根据位数动态构造它。

#2


2  

Use the # character for optional positions in the string:

在字符串中使用#字符作为可选位置:

string.Format("{0:#,###,##0.000}", number);

I don't think you can control the number of decimal places like that as the precision of the double will likely mess things up.

我不认为你可以控制像这样的小数位数,因为双精度的精度可能会搞砸了。

To encapsulate the logic of deciding how many decimal places to output you could look at creating a custom formatter.

要封装决定输出多少小数位的逻辑,您可以查看创建自定义格式化程序。

#3


2  

The first two String.Format in your question can be solved by automatically removing trailing zeros:

您问题中的前两个String.Format可以通过自动删除尾随零来解决:

String.Format("{0:#,##0.########}", number);

And the last one you could solve by calling Math.Round(number,1) for values over 1000 and then use the same String.Format.

最后一个可以通过调用Math.Round(数字,1)来解决超过1000的值,然后使用相同的String.Format。

Something like:

String.Format("{0:#,##0.########}", number<1000 ? number : Math.Round(number,1));

#4


2  

Following up on OwenP's (and by "extension" tvanfosson):

跟进OwenP(以及“扩展”tvanfosson):

If it's common enough, and you're on C# 3.0, I'd turn it into an extension method on the double:

如果它足够常见,并且你在C#3.0上,我会把它变成双重的扩展方法:

class MyExtensions 
{
    public static string ToFormmatedString(this double d)
    {
        // Take d and implement tvanfosson's code
    }
}

Now anywhere you have a double you can do:

现在你可以在任何地方获得双倍:

double d = 1.005343;
string d_formatted = d.ToFormattedString();

#5


1  

If it were me, I'd write a custom wrapper class and put tvanfosson's code into its ToString method. That way you could still work with the double value, but you'd get the right string representation in just about all cases. It'd look something like this:

如果是我,我会编写一个自定义包装类并将tvanfosson的代码放入其ToString方法中。这样你仍然可以使用double值,但几乎在所有情况下你都能获得正确的字符串表示。它看起来像这样:

class FormattedDouble
{ 
    public double Value { get; set; }

    protected overrides void ToString()
    {
        // tvanfosson's code to produce the right string
    }
}

Maybe it might be better to make it a struct, but I doubt it would make a big difference. You could use the class like this:

也许把它作为结构可能更好,但我怀疑它会产生很大的不同。你可以使用这样的类:

var myDouble = new FormattedDouble();
myDouble.Value = Math.Pi;
Console.WriteLine(myDouble);

#1


15  

Use Math.Log10 of the absolute value of the double to figure out how many 0's you need either left (if positive) or right (if negative) of the decimal place. Choose the format string based on this value. You'll need handle zero values separately.

使用double的绝对值的Math.Log10来计算你需要多少0的小数位左边(如果是正数)或右边(如果是负数)。根据此值选择格式字符串。您需要单独处理零值。

string s;
double epislon = 0.0000001; // or however near zero you want to consider as zero
if (Math.Abs(value) < epislon) {
    int digits = Math.Log10( Math.Abs( value ));
    // if (digits >= 0) ++digits; // if you care about the exact number
    if (digits < -5) {
       s = string.Format( "{0:0.000000000}", value );
    }
    else if (digits < 0) {
       s = string.Format( "{0:0.00000})", value );
    }
    else {
       s = string.Format( "{0:#,###,###,##0.000}", value );
    }
}
else {
    s = "0";
}

Or construct it dynamically based on the number of digits.

或者根据位数动态构造它。

#2


2  

Use the # character for optional positions in the string:

在字符串中使用#字符作为可选位置:

string.Format("{0:#,###,##0.000}", number);

I don't think you can control the number of decimal places like that as the precision of the double will likely mess things up.

我不认为你可以控制像这样的小数位数,因为双精度的精度可能会搞砸了。

To encapsulate the logic of deciding how many decimal places to output you could look at creating a custom formatter.

要封装决定输出多少小数位的逻辑,您可以查看创建自定义格式化程序。

#3


2  

The first two String.Format in your question can be solved by automatically removing trailing zeros:

您问题中的前两个String.Format可以通过自动删除尾随零来解决:

String.Format("{0:#,##0.########}", number);

And the last one you could solve by calling Math.Round(number,1) for values over 1000 and then use the same String.Format.

最后一个可以通过调用Math.Round(数字,1)来解决超过1000的值,然后使用相同的String.Format。

Something like:

String.Format("{0:#,##0.########}", number<1000 ? number : Math.Round(number,1));

#4


2  

Following up on OwenP's (and by "extension" tvanfosson):

跟进OwenP(以及“扩展”tvanfosson):

If it's common enough, and you're on C# 3.0, I'd turn it into an extension method on the double:

如果它足够常见,并且你在C#3.0上,我会把它变成双重的扩展方法:

class MyExtensions 
{
    public static string ToFormmatedString(this double d)
    {
        // Take d and implement tvanfosson's code
    }
}

Now anywhere you have a double you can do:

现在你可以在任何地方获得双倍:

double d = 1.005343;
string d_formatted = d.ToFormattedString();

#5


1  

If it were me, I'd write a custom wrapper class and put tvanfosson's code into its ToString method. That way you could still work with the double value, but you'd get the right string representation in just about all cases. It'd look something like this:

如果是我,我会编写一个自定义包装类并将tvanfosson的代码放入其ToString方法中。这样你仍然可以使用double值,但几乎在所有情况下你都能获得正确的字符串表示。它看起来像这样:

class FormattedDouble
{ 
    public double Value { get; set; }

    protected overrides void ToString()
    {
        // tvanfosson's code to produce the right string
    }
}

Maybe it might be better to make it a struct, but I doubt it would make a big difference. You could use the class like this:

也许把它作为结构可能更好,但我怀疑它会产生很大的不同。你可以使用这样的类:

var myDouble = new FormattedDouble();
myDouble.Value = Math.Pi;
Console.WriteLine(myDouble);