Embedded curly brackets in a call to String.Format

  • Thread starter Thread starter Chuck Heatherly
  • Start date Start date
C

Chuck Heatherly

Hi,

I am encountering a serious problem with using String.Format(string format, params object[] args). If I try to format a
string that happens to include curly brackets that are not intended to be format specifiers, then I get this exception
thrown:

System.FormatException: Input string was not in a correct format.
at System.Text.StringBuilder.FormatError()
at System.Text.StringBuilder.AppendFormat(IFormatProvider provider, String format, Object[] args)
at System.String.Format(IFormatProvider provider, String format, Object[] args)

Basically, what I am doing is writing a Logger class that handles log files. I have two main methods in this class that
I route all of my output through:

public void Write(string format, params object[] args);
public void WriteLine(string format, params object[] args);

But I am hitting a problem when the format variable happens to contain curly brackets that are not used as format
specifiers (i.e., I mean an embedded string like "{one two}" as opposed to {0}, {1}, etc.)

I guess I could quit using these types of functions and just concatenate strings together, but that is a lot of extra
memory allocation, and I really like the compact format of the method with the parameter array.

Here's a Short But Complete Program(tm):

using System;

namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
string s = String.Format("This is fine: {0}, but this is not: {some text}.", 1);
}
}
}

Thanks,
Chuck
 
Hi,

I am encountering a serious problem with using String.Format(string format, params object[] args). If I try to format a
string that happens to include curly brackets that are not intended to be format specifiers, then I get this exception
thrown:

I forgot to add one thing:

I am familiar with this part in the doc for format specifiers (MSDN article titled "Composite Formatting") that says:

The matching braces ("{" and "}") are required. Because opening and closing braces are interpreted as starting and
ending a format item, you must specify two opening braces ("{{") in the fixed text to display one opening brace ("{"),
and specify two closing braces ("}}") in the fixed text to display one closing brace ("}").

However, I don't have total control over how these strings are created. Sometimes I am dumping data from a database, so
the idea of pre-parsing these strings to have to double-up the curly brackets seems a litte crazy.

Chuck
 
I guess you'll just have to double them though. If the string is stored in
the database, double them there.

Otherwise, don't pass a string as the format specifier unless you can trust
it to be safe. You should not just pass any string you're given.

If you insist on passing the strings then you _must_ specify to whomever is
creating them how they must be formatted.

Look at it this way, Microsoft is telling you (us) what may and may not be
done, we deviate from that at our peril. Simply pass that on to your users
(or whatever).

If you have no say, you can't trust it, so don't pass it.
 
It might seem a little crazy, but the formatter doesn't have built in
functionality to "guess" which braces to use and which to ignore. You have
to tell it and for that you'll need to build a clever parser that will know
which ones are for format specifiers and which ones are to be ignored.

If things like '{1}' is something that you could find in the strings you
want to show, you'll have to consider other means, i.e. not use the
formatter. Change your format specifier to something like "@1@" and use
string.Replace() to substitute you parameters.

Just a thought...


Chuck Heatherly said:
Hi,

I am encountering a serious problem with using String.Format(string
format, params object[] args). If I try to format a
string that happens to include curly brackets that are not intended to be
format specifiers, then I get this exception
thrown:

I forgot to add one thing:

I am familiar with this part in the doc for format specifiers (MSDN
article titled "Composite Formatting") that says:

The matching braces ("{" and "}") are required. Because opening and
closing braces are interpreted as starting and
ending a format item, you must specify two opening braces ("{{") in the
fixed text to display one opening brace ("{"),
and specify two closing braces ("}}") in the fixed text to display one
closing brace ("}").

However, I don't have total control over how these strings are created.
Sometimes I am dumping data from a database, so
the idea of pre-parsing these strings to have to double-up the curly
brackets seems a litte crazy.

Chuck
 
It might seem a little crazy, but the formatter doesn't have built in
functionality to "guess" which braces to use and which to ignore. You have
to tell it and for that you'll need to build a clever parser that will know
which ones are for format specifiers and which ones are to be ignored.

If things like '{1}' is something that you could find in the strings you
want to show, you'll have to consider other means, i.e. not use the
formatter. Change your format specifier to something like "@1@" and use
string.Replace() to substitute you parameters.

Just a thought...

Jako and PIEBALD,

Thanks for your quick responses to my question. I have decided that I can't
spend the time pre-parsing the strings to double up the brackets, so I am going
to quit using the variations of Write and WriteLine that use a parameter array
argument and just use the overloads that take a single string argument.
Hopefully all those tiny memory allocations required to build up a string from
pieces won't be a problem.

Chuck
 
Chuck,
Forgive the late response... I figured I would post this anyway in case any
one else was interested!
I have decided that I can't
spend the time pre-parsing the strings to double up the brackets, so I am
going
to quit using the variations of Write and WriteLine that use a parameter
array
argument and just use the overloads that take a single string argument.
You can use a Regular Expression to "double up the brackets", something
like:

Const pattern As String =
"\{(?!\d+(,[+|-]?\d+)?(.*?)?)(?<value>.*?)\}"
Const replacement As String = "{{${value}}}"
Static parser As New Regex(pattern, RegexOptions.Compiled)

Dim input As String = "I mean an {embedded} string like ""{one
two}"" as opposed to {0}, {1}, etc"
Dim format As String = parser.Replace(input, replacement)

Debug.WriteLine(String.Format(format, 100, 200), "result")


The pattern says match all strings between {}, except those that match a
Composite Format specification "{index[,alignment][:formatString]}". I've
tried it with as many different format strings as I could & it appears to
work... I did not play with multi-line input strings, strings with a CR or
LF between the {}!

Hope this helps
Jay
 
Back
Top