String.Format exception when format string contains "{"
Asked Answered
J

5

37

I am using VSTS 2008 + C# + .Net 2.0. When executing the following statement, there is FormatException thrown from String.Format statement, any ideas what is wrong?

Here is where to get the template.html I am using. I want to format this part m={0} in template.html.

    string template = String.Empty;
    using (StreamReader textFile = new StreamReader("template.html"))
    {
        template = textFile.ReadToEnd();
        String.Format(template, "video.wmv");
    }

http://www.mediafire.com/download.php?u4myvhbmmzg

EDIT 1:

Here is the content for my template.html,

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<!-- saved from url=(0014)about:internet -->
<head>
    <title>Silverlight Project Test Page </title>

    <style type="text/css">
    html, body {
        height: 100%;
        overflow: auto;
    }
    body {
        padding: 0;
        margin: 0;
    }
    #silverlightControlHost {
        height: 100%;
    }
    </style>

    <script type="text/javascript">
        function onSilverlightError(sender, args) {

            var appSource = "";
            if (sender != null && sender != 0) {
                appSource = sender.getHost().Source;
            } 
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;

            var errMsg = "Unhandled Error in Silverlight 2 Application " +  appSource + "\n" ;

            errMsg += "Code: "+ iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";

            if (errorType == "ParserError")
            {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError")
            {           
                if (args.lineNumber != 0)
                {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " +  args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }

            throw new Error(errMsg);
        }
    </script>
</head>

<body>
    <!-- Runtime errors from Silverlight will be displayed here.
    This will contain debugging information and should be removed or hidden when debugging is completed -->
    <div id='errorLocation' style="font-size: small;color: Gray;"></div>

    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="500" height="240">
            <param name="source" value="ClientBin/VideoPlayer.xap"/>
            <param name="onerror" value="onSilverlightError" />
            <param name="background" value="white" />
            <param name="initParams" value="cc=true,markers=true,m={0}" />
            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
            </a>
        </object>
        <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
    </div>
</body>
</html>

thanks in avdance, George

Johniejohnna answered 13/7, 2009 at 9:45 Comment(2)
As suspected, there are braces in both the styles and the javascript. That won't work unless you escape them, as string.Format finds a { and panics when it can't find an integer and a }.Epa
btw; you aren't currently catching the result of string.Format (.NET strings are immutable, so string.Format returns a new string; it doesn't update the input string)Epa
E
69

At a guess, the html contains javascript or another source of braces ({ and }) which would all need doubling (to {{ and }}) to be usable with string.Format. I expect a different (more obvious) token may be in order, i.e. %%FILENAME%%. Then use either regex or string.Replace.

If you have a single tag, string.Replace is fine; if you have lots, there are tricks with regex and MatchEvaluator that may be helpful - like so but with a different regex pattern.


Update after the example html added: I would definitely use a different token; at the most basic level:

<param name="initParams" value="cc=true,markers=true,m=%%FILENAME%%" />

and

template = template.Replace("%%FILENAME%%", "video.wmv");
Epa answered 13/7, 2009 at 9:47 Comment(4)
I second this check for other curly brackets.Coprology
Cool, Marc, I like your smart solution.Johniejohnna
Marc, could you explain what do you mean "would all need doubling (to {{ and }}) to be usable with string.Format", I am confused what means need doubling to be usable with string.Format.Johniejohnna
If the brace isn't part of a replacement token (i.e. it isn't {0}), then that brace needs to be doubled to that string.Format understands what you mean. i.e. string.Format("this {{ is {0} a }} test", 6) should return "this { is 6 a } test". When it sees a {{ or }} it replaces it with a single { or } in the result, and doesn't attempt to treat it as a token like {0}, {1} etc.Epa
I
20

Your template contains { and } characters which need to be escaped, otherwise they confuse String.Format. Escape them using {{ and }}. Alternatively, use a different mechanism such as String.Replace.

Idaidae answered 13/7, 2009 at 9:48 Comment(1)
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?Johniejohnna
J
7

string.Format() does not handle { and } in the format string. You need to replace { with {{ and } with }} everywhere in your template.html file. Except for the single place where you use the {0} placeholder.

Not very elegant.

Instead, consider using a template engine. See http://csharp-source.net/open-source/template-engines for some suggestions.

The next-best solution is to use regexes (with MatchEvaluator) or string.Replace(), as suggested by other answers.

Edit:

Here's an example using the StringTemplate template engine:

StringTemplate htmlpage = new StringTemplate(File.ReadAllText("template.html"));
htmlpage.SetAttribute("content", "video.wmv");
Console.WriteLine(htmlpage.ToString());

Change a single line in your template.html file:

from:

<param name="initParams" value="cc=true,markers=true,m={0}" />

to:

<param name="initParams" value="cc=true,markers=true,m=$content$" />

When the template engine encounters $content$ in the template, it replaces it with the value of the 'content' attribute that you set using code.

Using StringTemplate, you can do simple looping and conditionals within your template. See the documentation.

Jeffereyjefferies answered 13/7, 2009 at 9:56 Comment(3)
Agreed. string.Format is a lousy template engine because of the way it handles braces ({ and }).Chuck
Hi codeape, I studied template engine, but confused why and how template engine relates to my question?Johniejohnna
Hi Joe, how template engine relates to my question? I am confused, any comments?Johniejohnna
C
1

Wat are the contents of the 'template' variable ?

Difficult to say what 's wrong with your code, but presumably, the template variable does not contain a string which as a place-holder. (Like "this is some string {0}").

I think that you should make use of the tools your IDE provides: debug the code, use watches to inspect the contents of the template variable.

Canale answered 13/7, 2009 at 9:47 Comment(1)
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?Johniejohnna
C
0

Whats in the template file?

if there are curly brackets that are not of the format {int} or there are more than there are arguments for the format statement, it'll throw an exception.

What is the message in the exception?

It's your Css thats doing it. As somoene else mentioned you'll need to doa regex replace, or a bunch of String.Replace commands in a row mark you variables with %%VARIABLE_NAME%% and use string replacement to replace them

Coprology answered 13/7, 2009 at 9:48 Comment(2)
I have posted my template.html into my original post in EDIT 1 section, any ideas what is wrong?Johniejohnna
Not having {0} does not cause an exception. The parameters will simply be ignored.Chuck

© 2022 - 2024 — McMap. All rights reserved.