当格式字符串包含“{”时,使用String.Format会出现异常。

37

我正在使用VSTS 2008 + C# + .Net 2.0。执行以下语句时,String.Format语句会抛出FormatException异常,有什么想法吗?

这里是获取我使用的template.html模板的位置。我想在template.html中格式化m={0}这部分。

    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

编辑 1:

这是我的 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>

谢谢提前帮助,George


1
正如我们所猜测的那样,两种风格的JavaScript代码中都有大括号。如果不对它们进行转义,这将无法正常工作,因为string.Format会查找{,并在找不到整数和}时出现错误。 - Marc Gravell
2
顺便提一下,您目前没有捕获 string.Format 的结果(.NET 字符串是不可变的,因此 string.Format 返回一个新的字符串;它不会更新输入字符串)。 - Marc Gravell
5个回答

69
猜测该HTML包含JavaScript或其他大括号({})的源代码,这些大括号需要加倍({{}})才能与string.Format一起使用。我建议使用不同(更明显)的标记,例如%%FILENAME%%,然后使用正则表达式或string.Replace进行替换。
如果你只有一个标签,那么使用string.Replace就可以了;如果你有很多标签,可以使用正则表达式和MatchEvaluator技巧,例如这里提供的示例,但需要使用不同的正则表达式模式。
在添加了示例HTML后进行更新:我肯定会使用不同的标记;最基本的层次上:
<param name="initParams" value="cc=true,markers=true,m=%%FILENAME%%" />

template = template.Replace("%%FILENAME%%", "video.wmv");

3
我赞同对其他花括号进行检查。 - Omar Kooheji
酷啊,Marc,我喜欢你的聪明解决方案。 - George2
Marc,你能解释一下你所说的“需要加倍(到{{和}})才能与string.Format一起使用”是什么意思吗?我不明白需要加倍才能与string.Format一起使用是什么意思。 - George2
如果大括号不是替换标记的一部分(即它不是{0}),那么该大括号需要加倍,以便string.Format理解您的意思。例如,string.Format("this {{ is {0} a }} test", 6) 应返回 "this { is 6 a } test"。当它看到{{或}}时,它会在结果中将其替换为单个{或},并且不会尝试将其视为像{0}、{1}等标记。 - Marc Gravell

20

您的模板中包含需要转义的{}字符,否则它们会让String.Format混淆。请使用{{}}进行转义。或者,使用另一种机制,如String.Replace


我已经在我的原始帖子的编辑1部分发布了template.html文件,有什么问题吗? - George2

7

string.Format()无法处理格式字符串中的{}。您需要在template.html文件中的每个位置将{替换为{{,将}替换为}},除了您使用{0}占位符的单个位置。

这并不是非常优雅。

相反,考虑使用模板引擎。请参见http://csharp-source.net/open-source/template-engines获取一些建议。

下一个最佳解决方案是使用正则表达式(带有MatchEvaluator)或string.Replace(),如其他答案所建议的。

编辑:

以下是使用StringTemplate模板引擎的示例:

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

在你的template.html文件中更改一行代码:

原始代码:

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

to:

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

当模板引擎在模板中遇到$content$时,它会用您使用代码设置的'content'属性的值来替换它。
使用StringTemplate,您可以在模板中进行简单的循环和条件语句。请参见文档

1
同意。string.Format是一个糟糕的模板引擎,因为它处理大括号({和})的方式。 - Joe Chung
嗨,codeape,我学习了模板引擎,但不明白为什么和如何与我的问题相关? - George2
嗨,乔,模板引擎如何与我的问题相关?我很困惑,有什么意见吗? - George2

1

'template'变量的内容是什么?

很难说你的代码出了什么问题,但可能是因为模板变量不包含一个带有占位符的字符串。(比如 "this is some string {0}")。

我认为你应该利用IDE提供的工具:调试代码,使用监视器检查模板变量的内容。


我已经在我的原始帖子中的EDIT 1部分发布了我的template.html模板,有什么想法是错的吗? - George2

0

模板文件里有什么?

如果花括号不是 {int} 格式,或者格式语句的参数数量超过了花括号的数量,就会抛出异常。

异常信息是什么?

这是你的 CSS 引起的。正如其他人提到的,你需要进行正则表达式替换,或一系列 String.Replace 命令来标记变量为 %%VARIABLE_NAME%%,并使用字符串替换来替换它们。


我已经在我的原始帖子中的EDIT 1部分发布了我的template.html模板,有什么想法是错的吗? - George2
1
没有{0}不会引发异常。参数将被忽略。 - Joe Chung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接