在 C#/.NET 中,格式化字符串主要有两种机制:String.Format() 和字符串内插。
String.Format() 接受一个字符串(文档中称为_复合格式_),它由固定文本和占位符(文档中称为格式项)组成,另外还接受数量可变的实参。返回值会用对应的实参解析每个格式项,并把解析后的值与固定文本组合起来。
string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25));
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
这种机制在技术上称为_复合格式_。
内插字符串以 $ 为前缀,并在大括号中包含运行时表达式。格式项的语法如下:$"{<interpolationExpression>}"。有了它,就不再需要单独列出实参了。其结果在功能上等同于 String.Format() 机制。
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
大括号中的文本,在复合格式中即占位符,在字符串内插中即内插表达式,都称为_格式项_。
一个格式项最多可以包含 3 个部分。第一部分是必需的表达式或实参占位符,如上面的示例代码所示。此外,还可以有一个可选的对齐(用逗号“,”引入)和一个可选的_格式字符串_(用冒号“:”引入)。
{<interpolationExpression>[,<alignment>][:<formatString>]}
_对齐_指定文本所放入的“字段”的长度:对齐为正数时在左侧用空格填充,为负数时在右侧填充。
_格式字符串_指定文本输出的形式,例如数字是否包含千位分隔符,或者是否只输出 DateTime 对象的日期部分。
下面的代码演示了如何显示 DateTime 对象的数据部分,以及如何以指数形式显示浮点数。
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
string.Format(
"I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
loadsOf, thatDay)
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
数字和日期都有标准格式和自定义格式。_自定义_格式和_标准_格式之间没有本质区别,只是自定义格式让你有机会用格式字母自行组合出格式字符串。
每个线程都有一个默认区域性 Thread.CurrentThread.CurrentCulture,它封装在 CultureInfo 的实例中。线程的区域性决定了日期和数字的格式化方式,其中会考虑地区差异,比如英国惯用的 DD/MM/YYYY 和美国惯用的 MM/DD/YYYY 之间的日期格式差异。
CultureInfo 实现了 IFormatProvider 接口,该接口可以传给 String.Format() 的某些重载。这样可以覆盖线程的区域性。
逐字字符串允许字符串跨越多行,以 @ 开头。
string str = @"
See no wretched
quotes everywhere
";
在这个练习中,你要帮助一对高中情侣在社交媒体上公开表白他们的爱意。
请实现静态方法HighSchoolSweethearts.DisplaySingleLine(),它接收两个名字,并将它们用一个爱心分隔后显示出来。
格式化后的文本宽度应为 61 个字符,爱心位于字符串的正中央。
所有名字都保证能轻松容纳在这一行的宽度之内。
HighSchoolSweethearts.DisplaySingleLine("Lance Green", "Pat Riley");
// => " Lance Green ♡ Pat Riley "
实现静态方法HighSchoolSweethearts.DisplayBanner(),它显示两组姓名首字母,并用加号分隔。
HighSchoolSweethearts.DisplayBanner("L. G.", "P. R.");
// see the ascii art below
****** ******
** ** ** **
** ** ** **
** * **
** **
** L. G. + P. R. **
** **
** **
** **
** **
** **
** **
***
*
实现静态方法HighSchoolSweethearts.DisplayGermanExchangeStudents(),为我们的德国交换生显示恋爱开始的日期以及在一起的时间长度。
HighSchoolSweethearts.DisplayGermanExchangeStudents("Norbert", "Heidi", new DateTime(2019, 1, 22), 1535.22f);
// => "Norbert and Heidi have been dating since 22.01.2019 - that's 1.535,22 hours"