String Formatting FAQ
Largly modivated by your comments on a recent post, Kit George recently posted a FAQ on string formatting on the BCL Website.
A couple of interesting items below... or suggest your own.
How do I write out a curly bracket in string formats?
In order to print out a curly bracket in a string using string formatting, simply put two of the curly brackets in a row. This is referred to as 'escaping' the curly bracket.
[C#]string s = String.Format("{{ hello to all }}");Console.WriteLine(s); //prints '{ hello to all }' |
Do escaped curly brackets have any odd behaviors I need to be aware of?
There is an interesting result from the decision to use two curly brackets in order to print a single curly bracket in a format string.
If you want to actually use the standard ability to use a referenced parameter in string formatting, you might write this kind of code:
[C#]int i = 42;string s = String.Format("{0}", i); //prints '42' |
However, what if I want to print out '{42}'? It would seem that this line of code is fairly intuitive, based on my attempt to escape the curly brackets:
[C#]int i = 42;string s = String.Format("{{{0}}}", i); //prints '{42}' |
Now however, I want to take advantage of some of the more robust formatting options available, and specify a format for the variable. I want to print it out in Number format, using the N specifier:
[C#]int i = 42;string s = String.Format("{0:N}", i); //prints '42.00' |
Going a step further, I want to print out my value with curly brackets around it, using the Number format specifier. So, I expected this to work:
[C#]int i = 42;string s = String.Format("{{{0:N}}}", i); //prints '{N}' |
The question is, why did this last attempt fail? There's two things you need to know in order to understand this result:
- When providing a format specifier, string formatting takes these steps:
- Determine if the specifier is longer than a single character: if so, then assume that the specifier is a custom format. A custom format will use suitable replacements for your format, but if it doesn't know what to do with some character, it will simply write it out as a literalliterals found in the format
- Determine if the single character specifier is a supported specifier (such as 'N' for number formatting). If it is, then format appropriately. If not, throw an ArgumnetException
- When attempting to determine whether a curly bracket should be escaped, the curly brackets are simply treated in the order they are received. Therefore, "{{{" will escape the first two characters and print the literal '{', and the the third curly bracket will begin the formatting section. On this basis, in "}}}" the first two curly brackets will be escaped, therefore a literal '}' will be written to the format string, and then the last curly bracket will be assumed to be ending a formatting section
With this information, we now can figure out what's occurring in our "{{{0:N}}}" situation. The first two curly brackets are escaped, and then we have a formatting section. However, we then also escape the closing curly bracket, before closing the formatting section. Therefore, our formatting section is actually interpreted as containing "0:N}".
Now, the formatter looks at the format specifier and it sees "N}" for the specifier. It therefore interprets this as a custom format, and since neither N or } mean anything for a custom numeric format, these characters are simply written out, rather than the value of the variable referenced.
This last bit gets a little confusing, but it becomes clearer if we compare this behavior with something like the following:
[C#]int i = 42;string s = String.Format("{0:N!}", i); //prints 'N!' |
The same thing occurs in this situation, but it's a little clearer, because we don't have any escaping. Basically, the format specifier is seen as "N!", which gets interpreted as a custom format (longer than one character), and because the custom format has nothing special to do with numbers, then N! is simply used for the value.
Comments
- Anonymous
January 16, 2004
Just curious, was there a reason you didn't use an easier-to-parse syntax? I personally dislike the "double the char to escape it" system because I find it harder to read and it leads to hard-to-grok parsing situations like the ones you described.
I like how Perl regexs work, if you want to escape a special character, you just put a backslash in front of it. /./ means "match any non-newline char" while /./ means "match a period"
I would much rather use "{{0}}" instead of "{{{0}}}" - Anonymous
January 17, 2004
Mike,
What you propose as "{{0}}" String.Format would actually see as "{{0}}". What you'd really need to pass in is "{{0}}", so that it sees the \ you entered as a single . I imagine this may be easier to enter in VB or maybe using C#'s @"" string format.
Even your way it's not easy to get it right :) - Anonymous
February 03, 2004
For those who seek:
Solution to the last challenge :
String.Format("{0}{1:N}{2}", "{",i,"}") - Anonymous
February 13, 2004
Another solution would be this:
string s = String.Format("{{{0}}}", i.ToString("N")); - Anonymous
October 06, 2006
When working on .NET projects, we often need to find the right API or the proper parameters to pass in