简体   繁体   中英

Can this be done with formatting strings alone?

I think I've found something that can't be done with formatting strings alone: I'm needing a string that would allow me to format a double to show no decimals and so that:

  • Numbers are thousand separated
  • 0 shows a dash
  • Negative numbers are shown between parentheses
  • 0.5 is rounded to 1, and -0.5 to -1
  • 0.4999.. is rounded to 0, and -0.4999... to -0 (which must be shown as "(0)")

I've arrived to this.

"{0:#,0;(#,0);-}"

But, this is showing those numbers between (-0.5 and 0.5) as "-". If I replace it with the following.

"{0:#,0.#;(#,0.#);-}"

This works "ok", except that it'll show numbers with decimal points, and I need them rounded.

For illustration purposes, I've tried with:

string format = "#,0;(#,0);-";

Console.WriteLine(1000000.ToString(format));
Console.WriteLine(1000.ToString(format));
Console.WriteLine(100.ToString(format));
Console.WriteLine(10.ToString(format));
Console.WriteLine(1.ToString(format));
Console.WriteLine(0.5.ToString(format));
Console.WriteLine(0.4.ToString(format));
Console.WriteLine(0.ToString(format));
Console.WriteLine((-0.4).ToString(format));
Console.WriteLine((-0.5).ToString(format));
Console.WriteLine((-1).ToString(format));
Console.WriteLine((-1000000).ToString(format));

Which gives:

1,000,000
1,000
100
10
1
1
-
-
-
(1)
(1)
(1,000,000)

And:

string format = "#,0.#;(#,0.#);-";

Console.WriteLine(1000000.ToString(format));
Console.WriteLine(1000.ToString(format));
Console.WriteLine(100.ToString(format));
Console.WriteLine(10.ToString(format));
Console.WriteLine(1.ToString(format));
Console.WriteLine(0.5.ToString(format));
Console.WriteLine(0.4.ToString(format));
Console.WriteLine(0.ToString(format));
Console.WriteLine((-0.4).ToString(format));
Console.WriteLine((-0.5).ToString(format));
Console.WriteLine((-1).ToString(format));
Console.WriteLine((-1000000).ToString(format));

Which outputs:

1,000,000
1,000
100
10
1
0.5
0.4
-
(0.4)
(0.5)
(1)
(1,000,000)

But this is what I'm trying to achieve:

1,000,000
1,000
100
10
1
1
0
-
(0)
(1)
(1)
(1,000,000)

So I'm settling for using the first format string and then re-processing those values that come out as "-", but I wonder if there's a way to do this with the format string alone.

Thanks for any help!

Can this be done with formatting strings alone?

No.

https://msdn.microsoft.com/en-us/library/0c899ak8%28v=vs.110%29.aspx#SectionSeparator

Three sections

The first section applies to positive values, the second section applies to negative values, and the third section applies to zeros .

If the number to be formatted is nonzero, but becomes zero after rounding according to the format in the first or second section , the resulting zero is formatted according to the third section.

(added emphasis)

As I read that, it doesn't seem to be possible, using a single format string, to ever get both a "0" and a "-" in the same set of outputs (with only the values changing). "0" will use the third format which you want to be "-".

Rather than just say 'no' - what can be done? Have you considered creating a method to output in the format you need?

You can do this with an extension method:

public static string ToStringZeroDash(this decimal value, string format)
{
    return value == 0 ? "-" : value.ToString(format);
}

example

(0.4).ToStringZeroDash("{0:#,0.#;(#,0.#);0}")

note the third part of the format is 0, but the extension returns "-" before it gets to there.

Edit: you might need (this double value .. or whatever the actual value type is and you could make the format optional/overloads using a default.

Edit: the above edit was to show I did read the question... I always use decimal so that floating point calculations are not an issue, which they can be as pointed out by weston in the comments. For completeness, here's a version for double :

public static string ToStringZeroDash(this double value, string format)
{
    const double tolerance = 0.0001;
    return Math.Abs(value) < tolerance ? "-" : value.ToString(format);
}

change tolerance (some call this 'epsilon') as required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM