C#中的字符串格式化

3

我正在学习字符串格式化"小抄",以便了解不同的字符串格式化参数如何影响字符串输出。在使用DateTime字符串格式化参数时,我写了这个小测试:

char[] dtFormats = new char[] { 'd', 'D', 'f', 'F', 'g', 'G', 'm', 'o', 'r', 's', 't', 'T', 'u', 'U', 'y' };
foreach (char format in dtFormats)
{
    Console.WriteLine("DateTime format {0} = {1:" + format + "}", format, DateTime.Now);
}

它所做的就是展示使用每个参数的DateTime的所有不同格式。

除此之外,我想重点关注这一点:

Console.WriteLine("DateTime format {0} = {1:" + format + "}", format, DateTime.Now);

现在我知道{0}会被格式化为(参数0),而{1:?}会被替换为DateTime.Now(参数1)

我尝试重新编写如下:

Console.WriteLine("DateTime format {0} = {1:{0}}", format, DateTime.Now);

这会引发一个“格式异常”,但我想知道为什么不能将字符串占位符嵌套在其他格式字符串占位符中。
在这种情况下,它应该用格式参数替换“{0}”,并用“DateTime.Now”替换“{1:{0}}”,后跟一个冒号和格式参数。
在C#中难道不可能吗?
编辑:
说到这,为什么Console.WriteLine("{{0}}", "Hello World");的结果是"{0}"而不是"{Hello World}"
5个回答

2

我们来简化一下吧。您试图嵌套大括号,但语法规定{{表示单个文字{。这就是您要找的内容:

Console.WriteLine("DateTime format {0} = {1}", format, DateTime.Now.ToString(format));

回答这个问题:

同样的,为什么Console.WriteLine("{{0}}", "Hello World");的结果是"{0}"而不是"{Hello World}"?

我再次强调,{{在语法上表示一个单独的文字{

如果你想使用冒号语法,你的方法是错误的。正确的写法应该是{100:C},它会以货币格式显示100。但是在这里你真的不需要这样做,因为让这种格式起作用将会很困难,因为你需要使用{1:{0}},而这将因为转义语法而失败。


这个案例有一个简单的解决方案(所以+1),但它并没有真正回答为什么你不能嵌套格式化占位符。也许我将不得不编写自己的字符串格式化实现... - Matthew Layton
@series0ne,我觉得我可能在你评论的时候正在编辑。请查看我的编辑。 - Mike Perrenoud

1
由于格式化字符串中的双大括号}}会转义大括号,因此它不起作用。
正如您所发现的那样:
string.Format("This {{is}} my {{escaped}} curlies");

如果您像这样转义它们,This {is} my {escaped} curlies是可以的,因为它们被转义了。但是如果您像您现在这样嵌套它们,解析器将无法确定是否要进行转义。

想象一下您是解析器,并遇到以下内容:

Console.WriteLine("DateTime format {0} = {1:{0}}", format, DateTime.Now);
/*                                            ^^ Okay, I'll escape this. WAIT!
                                                 .. now I have a two single
                                                 curly open braces. This is
                                                 a badly formatted format string
                                                 now.. FormatException!*/

啊,我明白了...Console.WriteLine("{{{0}}}", "Hello World"); 会输出 "{Hello World}"。 - Matthew Layton
但不幸的是,相同的原则似乎不能用于日期时间格式化 :-( - Matthew Layton

1
你可以尝试以下内容:
Console.WriteLine(string.Format("DateTime format {0} = {{1:{0}}}", format), format, DateTime.Now);

0
一个简单的步骤来确保你不会遇到字符被误解的问题,就是把应该放在每一边的内容区分开:对于左边,只需引用带有最少额外信息的块;对于右边,则需要尽可能复杂的块(而不仅仅是变量)。例如:
Console.WriteLine("DateTime format {0}{1}{2}", format, " = {" + DateTime.Now, ":" + format + "}");

或者甚至:

Console.WriteLine("{0}{1}{2}", "DateTime format " + format, " = {" + DateTime.Now, ":" + format + "}");

你甚至可以依赖于变量:

string chunk1 = "DateTime format " + format;
string chunk2 = " = {" + DateTime.Now;
string chunk3 = ":" + format + "}";
Console.WriteLine("{0}{1}{2}", chunk1, chunk2, chunk3);

0

在格式中,您不能引用任何参数。


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