Table 13.1 lists the format specifiers for number formatting. You can format numeric types using the ToString() method on the data types. The standard format specifier string consists of a special character followed by a sequence of digits specifying precision.
Listing 13.1 shows currency formatting. The format specifier to be used is C or c.
using System; using System.Globalization; using System.IO; public class NumericFormatting { static float NUMBER = 334.456F; public static void Main(string[] args) { TextWriter tw = Console.Out; PlainCurrencyFormatting(tw); CurrencyFormattingWithCustomProvider(tw); GreatBritainCurrencyFormatting(tw); } private static void PlainCurrencyFormatting(TextWriter tw) { tw.WriteLine(NUMBER.ToString("C")); tw.WriteLine(NUMBER.ToString("C6")); } private static void CurrencyFormattingWithCustomProvider (TextWriter tw) { NumberFormatInfo provider = new NumberFormatInfo(); provider.CurrencyDecimalDigits = 3; provider.CurrencySymbol= "$"; provider.CurrencyDecimalSeparator= "*"; tw.WriteLine(NUMBER.ToString("c", provider)); } private static void GreatBritainCurrencyFormatting(TextWriter tw) { CultureInfo culture = CultureInfo.CreateSpecificCulture("en-GB"); NumberFormatInfo provider = culture.NumberFormat; tw.WriteLine(NUMBER.ToString("c", provider)); } } |
Format Character | Description |
---|---|
C,c | Currency |
E,e | Scientific |
F,f | Fixed point |
G,g | General |
N,n | Number |
R,r | Roundtrip |
X,x | Hexadecimal |
The output of the Listing 13.1 is as follows:
$334.46 $334.456000 $334*456 £334.46
When no provider is specified, the number is formatted as $334.46, which uses the CultureInfo en-US (that is the equivalent of Locale.US). The $ symbol is used for the currency, and by default there are two digits after the decimal point, so the last digit (6) was the result of rounding. The third number in the output is a currency from a custom NumberFormatInfo. Note that the currency symbol had to be specified as $; it is not assumed to be $ by default. Because the plain instantiation of NumberFormatInfo is culture invariant, it makes no assumption about the currency symbol.
The next example is that of printing the same currency using the British pound. Note how the appropriate culture is obtained and the default NumberFormatInfo for that culture is used.
The E and e format specifiers can be used to format numbers in the scientific notation m.dddE+xxx. One digit always precedes the decimal point, and the number of decimal places is specified by the precision specifier, with six places used as the default. The format specifier controls whether E or e appears in the output. Listing 13.2 shows an example of scientific formatting.
using System; using System.Globalization; using System.IO; public class ScientificFormatting { static double NUMBER = 2345334.456547554D; public static void Main(string[] args) { TextWriter tw = Console.Out; PlainFormatting(tw); FormattingWithCustomProvider(tw); CultureSpecificFormatting(tw); } private static void PlainFormatting(TextWriter tw) { tw.WriteLine(NUMBER.ToString("E")); tw.WriteLine(NUMBER.ToString("E2")); tw.WriteLine(NUMBER.ToString("E4")); } private static void FormattingWithCustomProvider(TextWriter tw) { NumberFormatInfo provider = new NumberFormatInfo(); provider.NumberDecimalDigits = 2; tw.WriteLine(NUMBER.ToString("E", provider)); } private static void CultureSpecificFormatting(TextWriter tw) { CultureInfo culture = CultureInfo.CreateSpecificCulture("fr-FR"); NumberFormatInfo provider = culture.NumberFormat; tw.WriteLine(NUMBER.ToString("e", provider)); } } |
The output of Listing 13.2 is as follows:
2.345334E+006 2.35E+006 2.3453E+006 2.345334E+006 2,345334e+006
In Listing 13.2, the first method, PlainFormatting, merely modifies the number of digits that are put after the decimal point using the format specifier. The second method, FormattingWithCustomProvider, tries to limit the number of decimal digits to 2, but the runtime does not do so because of the E/e format specifier. The last method shows how French scientists would denote a number in exponential form.
The number format specified by the N or n specifier formats a number into a string that has commas. By default, the number is formatted with two digits to the right of the decimal point. You can control this by specifying the number of digits after the format specifier; for example, N4 or n4 would mean four digits after the decimal point.
The fixed-point format is similar to the number format except that it does not put commas into the formatted string. The general format string converts the value to either the fixed-point or the scientific format, whichever is more compact. Listing 13.3 gives examples of the three formats.
using System; using System.Globalization; using System.IO; public class ScientificFormatting { static float NUMBER = 85.56546F; public static void Main(string[] args) { TextWriter tw = Console.Out; //Using the {N,n} format specifiers tw.WriteLine("The number format"); PlainFormatting (tw, "n2"); FormattingWithCustomProvider(tw, "n"); CultureSpecificFormatting(tw, "n"); //Using the {G,g} format specifiers tw.WriteLine("The general format"); PlainFormatting (tw, "g2"); FormattingWithCustomProvider(tw, "g"); CultureSpecificFormatting(tw, "g"); //Using the fixed-point {F,f} format specifiers tw.WriteLine("The fixed-point format"); PlainFormatting (tw, "f2"); FormattingWithCustomProvider(tw, "f"); CultureSpecificFormatting(tw, "f"); //Using the % format specifiers tw.WriteLine("The % format"); PlainFormatting (tw, "###.##%"); FormattingWithCustomProvider(tw, "###.##%"); CultureSpecificFormatting(tw, "###.##%"); } private static void PlainFormatting(TextWriter tw, string pattern){ tw.WriteLine(NUMBER.ToString(pattern)); } private static void FormattingWithCustomProvider(TextWriter tw, string pattern) { NumberFormatInfo provider = new NumberFormatInfo(); provider.PercentDecimalDigits = 2; provider.PercentSymbol = "&"; tw.WriteLine(NUMBER.ToString(pattern, provider)); } private static void CultureSpecificFormatting(TextWriter tw, string pattern) { CultureInfo culture = CultureInfo.CreateSpecificCulture("fr-FR"); NumberFormatInfo provider = culture.NumberFormat; tw.WriteLine(NUMBER.ToString(pattern, provider)); } } |
The output of Listing 13.3 is as follows:
The number format 85.57 85.57 85,57 The general format 86 85.56546 85,56546 The fixed-point format 85.57 85.57 85,57 The % format 8556.55% 8556.55& 8556,55%
Note that when you use the French culture, the symbol “.” is replaced with a “,”. Note also that using the % specifier, the % symbol is changed to & in the last example because of the following statement in the code:
provider.PercentSymbol = "&" ;
Unlike Java, C# has no special percent formatter. However, the % symbol is used to indicate the percentage. The number is multiplied by 100 before it is displayed as a percentage. In Listing 13.3 the last method call shows percent formatting. Note that we introduced a new character in the format specifier. The next section discusses these custom format specifiers.
In addition to the standard format specifiers we have seen, you can specify custom format specifiers. Custom format specifiers are similar to the ones in Java. The special characters in Table 13.2 are used for specifying custom format strings and have similar meanings to the ones in Java.
In general, the zero character (0) is used as a digit or zero placeholder. If the numeric value has a digit in the position at which the 0 appears in the format string, the digit will appear in the result. If not, a zero appears in that position.
Throughout this chapter we have used the ToString() function to format numbers. However, format specifier strings can also be passed to the Console.WriteLine method to format the output at the time of printing.
The format specifiers follow the same syntax as when you specify them in the ToString() method, with a slight modification. Listing 13.4 shows how to use the format specifiers in the Console.WriteLine method. The specifier string is {0:00} here; the 00 after the : is the actual specifier. The 0 before the : indicates that the specifier is to be applied to the first argument of the Console.WriteLine call.
using System; public class ZeroFormatting { public static void Main(string[] args) { Console.WriteLine("{0:00}", 55); Console.WriteLine("{0:00000}", 556); Console.WriteLine("{0:00}", 66464); } } |
The output of Listing 13.4 is as follows:
55 00556 66464
The # character behaves similarly to the 0 character, except that the # character is omitted if there is no digit in that position. Listing 13.5 shows the use of the # character.
using System; public class HashFormatting { public static void Main(string[] args) { Console.WriteLine("{0:####}", 55); Console.WriteLine("{0:#}", 556); Console.WriteLine("{0:##}", 66464); } } |
The output of Listing 13.5 is as follows:
55 556 66464
Note that 556 is now not preceded with leading zeros.
The “,” character is used as a group separator. If a comma appears in the middle of a display digit placeholder (0 or #) and to the left of the decimal point, then a group separator will be inserted into the string. Listing 13.6 shows how this works.
using System; public class CommaFormatting { public static void Main(string[] args) { Console.WriteLine("{0:,###}", 55678); Console.WriteLine("{0:#,##}", 55678); Console.WriteLine("{0:#,#,#}", 55678); Console.WriteLine("{0:#,#,#}", 55678857); Console.WriteLine("{0:000#,.000}", 55678857); } } |
The output of Listing 13.6 is as follows:
55678 55,678 55,678 55,678,857 55678.857
Note that putting one comma first divides the number by 1,000 and places the comma at the appropriate location. Every subsequent comma added divides the number further by 1,000, and the commas are again added to appropriate places. You can scale a number by placing the comma character directly before the decimal point. For each comma present in this location, the number is divided by 1,000 before it is formatted.
Listing 13.7 shows the section, hexadecimal, and escaping specifiers. The section specifier is used to specify different formatting strings for a number depending on whether it is positive, negative, or zero. Sections are demarcated by a semicolon. If there are three sections (x;y;z), then format x would apply if the number were positive, format y would apply if the number were negative, and format z would apply if the number were zero.
using System; using System.Globalization; using System.IO; public class ScientificFormatting { static float NUMBER = 85.56546F; public static void Main(string[] args) { //Hexadecimal formatting Console.WriteLine("{0:X}", 58); //Section formatting Console.WriteLine("{0:##;#.000;(##.00)}", 57575.356); Console.WriteLine("{0:##,00;00.##;(##.00)}",-57575.356); Console.WriteLine("{0:##,00;00.##;(##.00)}", 0); //Escaping characters Console.WriteLine("{0:###;bs;bs#}", 345); } } |
The escaping specifier is in fact not a specifier but a way to escape characters so that they don't get interpreted at the time of formatting.
The output of Listing 13.7 is as follows:
3A 57575 57575.36 (.00) 345#
Notice that when the number is 0, the section specifier chooses the rightmost format for formatting the number.
3.17.184.90