Sunday, September 11, 2011

String.Format("{0}", "formatting string"};


One of the painful things about good old ASP was string formatting, VBScript simply didn't have anything useful. C# (and VB.Net) do, but MSDN doesn't provide a quick reference to the formatting options. So here's a quick reference.
To compare string formatting in C# to those in C lets have an example,
char szOutput[256];
sprintf(szOutput, "At loop position %d.\n", i);


sprintf takes an output buffer, a format string and any number of arguments to substitute into the format string.
The C# equivalent for sprintf is String.Format, which takes a format string and the arguments. It returns a string, and because you're not passing in a buffer there's no chance of a buffer overflow.
string outputString = String.Format("At loop position {0}.\n", i);

So why doesn't have the format argument have parameters specifying what data type you're formatting? The CLR objects have metadata which informs the CLR what the objects are, and each object has a standard ToString() method which returns a string representation of that object. Much nicer than C where if you passed the wrong type of variable into sprintf everything could come crashing down.
The ToString method can accept a string parameter which tells the object how to format itself. In the call to String.Format , the formatting string is passed after the position, for example, "{0:##}". The text inside the curly braces is {argumentIndex[,alignment][:formatString]}. If alignment is positive, the text is right-padding to fill the specified field length, if it's negative, it's left-padded.

formatting strings

There's not much formatting that can be applied to a string. Only the padding / alignment formatting options can be applied. These options are also available to every argument, regardless of type.
exampleoutput
String.Format("--{0,10}--", "test");--      test--
String.Format("--{0,-10}--", "test");--test      --

formatting numbers

Number formatting is culture dependant. For example, formatting a currency string on my laptop will return a result like £9.99, formatting a currency on a machine set for the US region would return $9.99.
specifiertypeformatoutput
(double 1.2345)
output
(int -12345)
ccurrency{0:c}£1.23-£12,345.00
ddecimal
(whole number)
{0:d}System.FormatException-12345
eexponent / scientific{0:e}1.234500e+000-1.234500e+004
ffixed point{0:f}1.23-12345.00
ggeneral{0:g}1.2345-12345
nnumber{0:n}1.23-12,345.00
rround trippable{0:r}1.23System.FormatException
xhexadecimal{0:x4}System.FormatExceptionffffcfc7

custom number formatting

specifiertypeformatoutput
(double 1234.56)
0zero placeholder{0:00.000}1234.560
#digit placeholder{0:#.##}1234.56
.decimal point placeholder{0:0.0}1234.6
,thousand separator{0:0,0}1,235
%percentage{0:0%}123456%

In addition there is the group separator; this is useful for varying the format, depending on the value of the parameter passed. For example
String.Format("{0:£#,##0.00;(£#,##0.00);Nothing}", value);

This will output "£1,240.00" if passed 1243.56.  It will output the same format bracketed if the value is negative "(£1,240.00)", and will output the string "Nothing" if the number is zero.

date formatting

Date formats are very dependant on the culture information passed. The examples below are shown using the UK culture.
specifiertypeoutput
(June 8, 1970 12:30:59)
dShort Date08/06/1970
DLong Date08 June 1970
tShort Time12:30
TLong Time12:30:59
fFull date and time08 June 1970 12:30
FFull date and time (long)08 June 1970 12:30:59
gDefault date and time08/06/1970 12:30
GDefault date and time (long)08/06/1970 12:30:59
MDay / Month8 June
rRFC1123 date stringMon, 08 Jun 1970 12:30:59 GMT
sSortable date/time1970-06-08T12:30:59
uUniversal time, local timezone1970-06-08 12:30:59Z
YMonth / YearJune 1970

custom date formatting

specifiertypeoutput
(June 8, 1970 12:30:59)
ddDay08
dddShort Day NameMon
ddddFull Day NameMonday
hh2 digit hour12
HH2 digit hour (24 hour)12
mm2 digit minute30
MMMonth06
MMMShort Month nameJun
MMMMMonth nameJune
ssseconds59
ttAM/PMPM
yy2 digit year70
yyyy4 digit year1970
:seperator, e.g. {0:hh:mm:ss}12:30:59
/seperator, e.g. {0:dd/MM/yyyy}08/06/1970

There are others, including time zone formatting and so on, but the ones above are the most commonly used.

culture information

string.format also provides a method which accepts a CultureInfo argument, as an IFormatProvider. This is important when trying to write portable and localisable code, as, for example, month names will change according to the local culture of the machine you are running on. Rather than simply call the standard String.Format you should consider always calling the overloaded culture method. If you don't need to specify a culture you can use the System.Globalization.CultureInfo.InvariantCulture. This will then default your formatting to English, as opposed to the culture of the current thread.

No comments:

Post a Comment