函数中{}输出格式详解(C#)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数中{}输出格式详解(C#)相关的知识,希望对你有一定的参考价值。
Console.WriteLine()函数中{}输出格式详解(C#)
Console.WriteLine()函数的格式一直没怎么注意。今天同事问起Console.WriteLine({0:D3},a)的意义,忽然发现不知道D代表什么意义。以前以为{0,4}是指第一个变量输出时占8位,今天查了一下,发现也并不完全正确。
其中格式项都采用如下形式:
{index[,alignment][:formatString]}
其中"index"指索引占位符,这个肯定都知道;
",alignment"按字面意思显然是对齐方式,以","为标记;
":formatString"就是对输出格式的限定,以":"为标记。
alignment:可选,是一个带符号的整数,指示首选的格式化字段宽度。如果“对齐”值小于格式化字符串的长度,“对齐”会被忽略,并且使用格式化字符串的长度作为字段宽度。如果“对齐”为正数,字段的格式化数据为右对齐;如果“对齐”为负数,字段的格式化数据为左对齐。如果需要填充,则使用空白。如果指定“对齐”,就需要使用逗号。
formatString:由标准或自定义格式说明符组成.
下表是从网上得来:
字符 |
说明 |
示例 |
输出 |
C | 货币 | string.Format("{0:C3}", 2) | $2.000 |
D | 十进制 | string.Format("{0:D3}", 2) | 002 |
E | 科学计数法 | 1.20E+001 | 1.20E+001 |
G | 常规 | string.Format("{0:G}", 2) | 2 |
N | 用分号隔开的数字 | string.Format("{0:N}", 250000) | 250,000.00 |
X | 十六进制 | string.Format("{0:X000}", 12) | C |
string.Format("{0:000.000}", 12.2) | 012.200 |
Specifier | Type | Format | Output (Passed Double 1.42) |
Output (Passed Int -12400) |
c | Currency | {0:c} | $1.42 | -$12,400 |
d | Decimal (Whole number) | {0:d} | System. FormatException |
-12400 |
e | Scientific | {0:e} | 1.420000e+000 | -1.240000e+004 |
f | Fixed point | {0:f} | 1.42 | -12400.00 |
g | General | {0:g} | 1.42 | -12400 |
n | Number with commas for thousands | {0:n} | 1.42 | -12,400 |
r | Round trippable | {0:r} | 1.42 | System. FormatException |
x | Hexadecimal | {0:x4} | System. FormatException |
cf90 |
Specifier | Type | Example (Passed System.DateTime.Now) |
d | Short date | 10/12/2002 |
D | Long date | December 10, 2002 |
t | Short time | 10:11 PM |
T | Long time | 10:11:29 PM |
f | Full date & time | December 10, 2002 10:11 PM |
F | Full date & time (long) | December 10, 2002 10:11:29 PM |
g | Default date & time | 10/12/2002 10:11 PM |
G | Default date & time (long) | 10/12/2002 10:11:29 PM |
M | Month day pattern | December 10 |
r | RFC1123 date string | Tue, 10 Dec 2002 22:11:29 GMT |
s | Sortable date string | 2002-12-10T22:11:29 |
u | Universal sortable, local time | 2002-12-10 22:13:50Z |
U | Universal sortable, GMT | December 11, 2002 3:13:50 AM |
Y | Year month pattern | December, 2002 |
Specifier | Type | Example | Example Output |
dd | Day | {0:dd} | 10 |
ddd | Day name | {0:ddd} | Tue |
dddd | Full day name | {0:dddd} | Tuesday |
f, ff, ... | Second fractions | {0:fff} | 932 |
gg, ... | Era | {0:gg} | A.D. |
hh | 2 digit hour | {0:hh} | 10 |
HH | 2 digit hour, 24hr format | {0:HH} | 22 |
mm | Minute 00-59 | {0:mm} | 38 |
MM | Month 01-12 | {0:MM} | 12 |
MMM | Month abbreviation | {0:MMM} | Dec |
MMMM | Full month name | {0:MMMM} | December |
ss | Seconds 00-59 | {0:ss} | 46 |
tt | AM or PM | {0:tt} | PM |
yy | Year, 2 digits | {0:yy} | 02 |
yyyy | Year | {0:yyyy} | 2002 |
zz | Timezone offset, 2 digits | {0:zz} | -05 |
zzz | Full timezone offset | {0:zzz} | -05:00 |
: | Separator | {0:hh:mm:ss} | 10:43:20 |
/ | Separator | {0:dd/MM/yyyy} | 10/12/2002 |
CSDN中例子:
- string myFName = "Fred";
- string myLName = "Opals";
- int myInt = 100;
- string FormatFName = String.Format("First Name = |{0,10}|", myFName);
- string FormatLName = String.Format("Last Name = |{0,10}|", myLName);
- string FormatPrice = String.Format("Price = |{0,10:C}|", myInt);
- Console.WriteLine(FormatFName);
- Console.WriteLine(FormatLName);
- Console.WriteLine(FormatPrice);
- FormatFName = String.Format("First Name = |{0,-10}|", myFName);
- FormatLName = String.Format("Last Name = |{0,-10}|", myLName);//-10指左对齐,10个宽度,
- FormatPrice = String.Format("Price = |{0,-10:C}|", myInt);//C指以货币形式输出
- Console.WriteLine(FormatFName);
- Console.WriteLine(FormatLName);
- Console.WriteLine(FormatPrice);
- //运行结果
- //First Name = | Fred|
- //Last Name = | Opals|
- //Price = | $100.00|
- //First Name = |Fred |
- //Last Name = |Opals |
- //Price = |$100.00 |
String 用法::
这种写法用过没:string.Format("{0,-10}", 8)
做 .net 开发也若干年了,如此写法(下面代码中黄色高亮部分)确是我第一次见(更别提用了):
1 2 3 4 | var s1 = string.Format("{0,-10}", 8); var s2 = string.Format("{0,10}", 8); var s3 = string.Format("{0,20:yyyy-MM-dd}", DateTime.Today); var s4 = string.Format("4G 内存便宜了{0,12:C2},我打算买{1,4}条", 145, 2) |
大括号中,索引后 分号前,有一个逗号和一个整数(减号表示负数)。
会格式化成为什么样子呢?看下调试截图吧:

从上图中能大致看出此端倪,没错:
tring.Format("{0,-10}", 8) 等同于 string.Format("{0}", 8).PadRight(10);
tring.Format("{0,10}", 8) 等同于 string.Format("{0}", 8).PadLeft(10)。
String.Format 方法 format 参数由零或多个文本序列与零或多个索引占位符混合组成,其中索引占位符称为格式项,对应于与此方法的参数列表中的对象。 格式设置过程将每个格式项替换为相应对象值的字符串表示形式。
格式项的语法如下:
{index[,length][:formatString]}
方括号中的元素是可选的。 下表描述每个元素。 有关复合格式设置功能(包括格式项的语法)的更多信息,请参见复合格式。
元素 | 说明 |
---|---|
索引 | 要设置格式的对象的参数列表中的位置(从零开始)。 如果由 index 指定的对象为 null,则格式项将被 String.Empty 替换。 由于该重载在其参数列表中只有单个对象,index 的值必须始终为 0。 如果 index 位置没有参数,将引发 FormatException。 |
,length | 参数的字符串表示形式中包含的最小字符数。 如果该值是正的,则参数右对齐;如果该值是负的,则参数左对齐。 |
:formatString | 要设置格式的对象支持的标准或自定义格式字符串。 formatString 的可能值与该对象的 ToString(format) 方法支持的值相同。 如果没有指定 formatString,并且要设置格式的对象实现了 IFormattable 接口,则将传递 null 作为用作 IFormattable.ToString 格式字符串的 format 参数的值。 |
元素
说明
索引
,length
参数的字符串表示形式中包含的最小字符数。 如果该值是正的,则参数右对齐;如果该值是负的,则参数左对齐。
:formatString
MSDN 原文链接:Format 方法 (String, Object)
,length 其实把 String.PadLeft 和 String.PadRight 的功能融合在的 String.Format 方法中,简化了代码的编写。
如果没有这种格式,代码写起来麻烦多了:
1 2 3 | var s5 = string.Format("4G 内存便宜了{0},我打算买{1}条", 145.ToString("C2").PadLeft(12), 2.ToString().PadLeft(4)) |
看起来不直观,复杂,如文首代码中的 “我打算买{1,4}条”。
实际使用少,没用过的看了很纳闷。
前言
如果你熟悉Microsoft Foundation Classes(MFC)的CString,Windows Template Library(WTL)的CString或者Standard Template Library(STL)的字符串类,那么你对String.Format方法肯定很熟悉。在C#中也经常使用这个方法来格式化字符串,比如下面这样:
int x = 16; decimal y = 3.57m; string h = String.Format( "item {0} sells at {1:C}", x, y ); Console.WriteLine(h)
在我的机器上,可以得到下面的输出:
item 16 sells at ¥3.57
也许你的机器上的输出和这个不太一样。这是正常的,本文稍后就会解释这个问题。
在我们日常使用中,更多的是使用Console.WriteLine方法来输出一个字符串。其实String.Format和Console.WriteLine有很多共同点。两个方法都有很多重载的格式并且采用无固定参数的对象数组作为最后一个参数。下面的两个语句会产生同样的输出。
Console.WriteLine( "Hello {0} {1} {2} {3} {4} {5} {6} {7} {8}", 123, 45.67, true, ‘Q‘, 4, 5, 6, 7, ‘8‘); string u = String.Format("Hello {0} {1} {2} {3} {4} {5} {6} {7} {8}", 123, 45.67, true, ‘Q‘, 4, 5, 6, 7, ‘8‘); Console.WriteLine(u)
输出如下:
Hello 123 45.67 True Q 4 5 6 7 8 Hello 123 45.67 True Q 4 5 6 7 8
2 字符串格式
String.Format和WriteLine都遵守同样的格式化规则。格式化的格式如下:"{ N [, M ][: formatString ]}", arg1, ... argN,在这个格式中:
1) N是从0开始的整数,表示要格式化的参数的个数
2) M是一个可选的整数,表示格式化后的参数所占的宽度,如果M是负数,那么格式化后的值就是左对齐的,如果M是正数,那么格式化后的值是右对齐的
3) formatString是另外一个可选的参数,表示格式代码
argN表示要格式化的表达式,和N是对应的。
如果argN是空值,那么就用一个空字符串来代替。如果没有formatString,那么就用参数N对应的ToString方法来格式化。下面的语句会产生同样的输出:
ublic class TestConsoleApp { public static void Main(string[] args) { Console.WriteLine(123); Console.WriteLine("{0}", 123); Console.WriteLine("{0:D3}", 123); } }
输出是:
123 123 123
也可以通过String.Format得到同样的输出。
tring s = string.Format("123"); string t = string.Format("{0}", 123); string u = string.Format("{0:D3}", 123); Console.WriteLine(s); Console.WriteLine(t); Console.WriteLine(u)
因此有如下结论:
(,M)决定了格式化字符串的宽度和对齐方向
(:formatString)决定了如何格式化数据,比如用货币符号,科学计数法或者16进制。就像下面这样:
Console.WriteLine("{0,5} {1,5}", 123, 456); // 右对齐 Console.WriteLine("{0,-5} {1,-5}", 123, 456); // 左对齐
输出是
123 456 123 456
也可以合并这些表达式,先放一个逗号,再放一个冒号。就像这样:
Console.WriteLine("{0,-10:D6} {1,-10:D6}", 123, 456)
输出是:
000123
000456
我们可以用这种格式化特性来对齐我们的输出。
Console.WriteLine("\\n{0,-10}{1,-3}", "Name","Salary"); Console.WriteLine("----------------"); Console.WriteLine("{0,-10}{1,6}", "Bill", 123456); Console.WriteLine("{0,-10}{1,6}", "Polly", 7890)
输出是:
Name Salary ---------------- Bill 123456 Polly 7890
3 格式化标识符
标准的数学格式字符串用于返回通常使用的字符串。它们通常象X0这样的格式。X是格式化标识符,0是精度标识符。格式标识符号共有9种,它们代表了大多数常用的数字格式。就像下表所示:
字母 | 含义 |
C或c | Currency 货币格式 |
D或d | Decimal 十进制格式(十进制整数,不要和.Net的Decimal数据类型混淆了) |
E或e | Exponent 指数格式 |
F或f | Fixed point 固定精度格式 |
G或g | General 常用格式 |
N或 | 用逗号分割千位的数字,比如1234将会被变成1,234 |
P或 | Percentage 百分符号格式 |
R或r | Round-trip 圆整(只用于浮点数)保证一个数字被转化成字符串以后可以再被转回成同样的数字 |
X或x | Hex 16进制格式 |
如果我们使用下面的表达方式,让我们看看会发生什么
ublic class FormatSpecApp { public static void Main(string[] args) { int i = 123456; Console.WriteLine("{0:C}", i); // ¥123,456.00 Console.WriteLine("{0:D}", i); // 123456 Console.WriteLine("{0:E}", i); // 1.234560E+005 Console.WriteLine("{0:F}", i); // 123456.00 Console.WriteLine("{0:G}", i); // 123456 Console.WriteLine("{0:N}", i); // 123,456.00 Console.WriteLine("{0:P}", i); // 12,345,600.00 % Console.WriteLine("{0:X}", i); // 1E240 } }
精度控制标识控制了有效数字的个数或者十进制数小数的位数。
R(圆整)格式仅仅对浮点数有效。这个值首先会用通用格式来格式化。对于双精度数有15位精度,对于单精度数有7位精度。如果这个值可以被正确地解析回原始的数字,就会用通用格式符来格式化。如果不能解析回去的话,那么就会用17位精度来格式化双精度数,用9位精度来格式化单精度数。尽管我们可以在圆整标识符后面添加有效数字的位数,但是它会被忽略掉。
double d = 1.2345678901234567890; Console.WriteLine("Floating-Point:\\t{0:F16}", d); // 1.2345678901234600 Console.WriteLine("Roundtrip:\\t{0:R16}", d); // 1.2345678901234567
如果标准格式化标识符还不能满足你。你可以使用图形化格式字符串来创建定制的字符串输出。图形化格式化使用占位符来表示最小位数,
最大位数,定位符号,负号的外观以及其它数字符号的外观。就像下表所示
符号 | 名称 | 含义 |
0 | 0占位符 | 用0填充不足的位数 |
# | 数字占位符 | 用#代替实际的位数 |
. | 十进制小数点 | |
, | 千位分隔符 | 用逗号进行千位分割,比如把1000分割成1,000 |
% | 百分符号 | 显示一个百分标识 |
E+0 E-0 e+0 e-0 | 指数符号 | 用指数符号格式化输出 |
\\ | 专一字符 | 用于传统格式的格式化序列,比如"\\n"(新行) |
‘ABC‘ "ABC" | 常量字符串 | 显示单引号或者双引号里面的字符串 |
区域分隔符 | 如果数字会被格式化成整数,负数,或者0,用;来进行分隔 | |
,. | 缩放符号 | 数字除以1000 |
看下面的例子:
double i = 123456.42; Console.WriteLine(); Console.WriteLine("{0:000000.00}", i); //123456.42 Console.WriteLine("{0:00.00000000e+0}", i); //12.34564200e+4 Console.WriteLine("{0:0,.}", i); //123 Console.WriteLine("{0:#0.000}", i); // 123456.420 Console.WriteLine("{0:#0.000;(#0.000)}", i); // 123456.420 Console.WriteLine("{0:#0.000;(#0.000);<zero>}", i); // 123456.420 Console.WriteLine("{0:#%}", i); // 12345642% i = -123456.42; Console.WriteLine(); Console.WriteLine("{0:000000.00}", i); //-123456.42 Console.WriteLine("{0:00.00000000e+0}", i); //-12.34564200e+4 Console.WriteLine("{0:0,.}", i); //-123 Console.WriteLine("{0:#0.000}", i); // -123456.420 Console.WriteLine("{0:#0.000;(#0.000)}", i); // (123456.420) Console.WriteLine("{0:#0;(#0);<zero>}", i); // (123456) Console.WriteLine("{0:#%}", i); // -12345642% i = 0; Console.WriteLine(); Console.WriteLine("{0:0,.}", i); //0 Console.WriteLine("{0:#0}", i); // 0 Console.WriteLine("{0:#0;(#0)}", i); // 0 Console.WriteLine("{0:#0;(#0);<zero>}", i); // <zero> Console.WriteLine("{0:#%}", i); // %
4 数字字符串的解析
所有的基础类型都有ToString方法,它是从object类型中继承过来的。所有的数值类型都有Parse方法,它用字符串为参数,并且返回相等的数值。比如
ublic class NumParsingApp { public static void Main(string[] args) { int i = int.Parse("12345"); Console.WriteLine("i = {0}", i); int j = Int32.Parse("12345"); Console.WriteLine("j = {0}", j); double d = Double.Parse("1.2345E+6"); Console.WriteLine("d = {0:F}", d); string s = i.ToString(); Console.WriteLine("s = {0}", s); } }
输出如下
i = 12345 j = 12345 d = 1234500.00 s = 12345
在缺省状况下,某些非数字字符是可以存在的。比如开头和结尾的空白。逗号和小数点,加号和减号,因此,下面的Parse语句是一样的
tring t = " -1,234,567.890 "; //double g = double.Parse(t); // 和下面的代码干同样的事情 double g = double.Parse(t, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite); Console.WriteLine("g = {0:F}", g)
输出都是这样
g = -1234567.89
注意到,如果你要使用NumberStyles,就要添加对System.Globalization的引用,然后就可以使用不同NumberStyles的组合或者其中的任意一种。如果你想兼容货币符号,就需要使用重载的Parse方法,它们采用了NumberFormatInfo对象作为一个参数,然后你可以设置NumberFormatInfo的CurrencySymbol属性来调用Parse方法,比如:
上面的代码有如下输出
h = -1234567.89
除了NumberFormatInfo,还可以使用CultureInfo类。CultureInfo代表了某种特定的文化,包括文化的名字,书写的方式,日历的格式。对于某种特定文化的操作是非常普遍的情况,比如格式化日期和排序。文化的命名方式遵从RFC1766标准,使用<语言代码2>-<国家/地区码2>的方式,其中的<语言代码2>是两个小写的字母,它们来自ISO639-1;<国家/地区码2>是两个大写字母,它们来自ISO3166。比如,美国英语是“en-US"。英国英语是"en-GB"。特立尼达和多巴哥英语是"en-TT"。例如,我们可以创建一个美国英语的CultureInfo对象并且基于这种文化将数字转换成字符串。
int k = 12345; CultureInfo us = new CultureInfo("en-US"); string v = k.ToString("c", us); Console.WriteLine(v)
输出是:
$12,345.00
要注意到,我们使用了重载的ToString方法,它把第一个格式化字符串当成第一个参数,将一个CultureInfo对象(执行了IFormatProvider对象)作为第二个参数。这儿有第二个例子,对于丹麦人来说:
CultureInfo dk = new CultureInfo("da-DK"); string w = k.ToString("c", dk); Console.WriteLine(w)
输出是:
kr 12.345,00
5 字符串和日期
一个日期对象有个叫Ticks的属性。它存储了自从公元1年的1月1号上午12点开始的,以100纳秒为间隔的时间。比如,Ticks值等于31241376000000000L表示公元100年,星期五,1月1号,上午12点这一时间。Ticks总是以100纳秒为间隔递增。
DateTime的值以存储在DateTimeFormatInfo实例里面的标准或者自定义的方式来表示。为了修改一个日期显示的方式,DateTimeFormatInfo实例必须要是可写的,以便我们写入自定义的格式并且存入属性中
using System.Globalization; public class DatesApp { public static void Main(string[] args) { DateTime dt = DateTime.Now; Console.WriteLine(dt); Console.WriteLine("date = {0}, time = {1}\\n", dt.Date, dt.TimeOfDay); } }
代码会产生下面的输出
23/06/2001 17:55:10 date = 23/06/2001 00:00:00, time = 17:55:10.3839296
下表列出了标准的格式字符串以及相关的DateTimeFormatInfo属性
D | ||
D | MM/dd/yyyy | ShortDatePattern(短日期模式) |
D | dddd,MMMM dd,yyyy | LongDatePattern(长日期模式) |
F | dddd,MMMM dd,yyyy HH:mm | Full date and time (long date and short time)(全日期和时间模式) |
F | dddd,MMMM dd,yyyy HH:mm: | FullDateTimePattern (long date and long time)(长日期和长时间) |
G | MM/dd/yyyy HH:mm | General (short date and short time)(通用模式,短日期和短时间) |
G | MM/dd/yyyy HH:mm: | General (short date and long time)(通用模式,短日期和长时间) |
M,M | MMMM dd | MonthDayPattern(月天模式) |
r,R | ddd,dd MMM yyyy,HH‘:‘mm‘:‘ss ‘GMT‘ | RFC1123Pattern (RFC1123模式) |
S | yyyy-MM-dd HH:mm: | SortableDateTimePattern (conforms to ISO 8601) using local time(使用本地时间的可排序模式) |
T | HH:mm | ShortTimePattern (短时间模式) |
T | HH:mm: | LongTimePattern(长时间模式) |
U | yyyy-MM-dd HH:mm: | UniversalSortable-DateTimePattern (conforms to ISO 8601) using universal time(通用可排序模式) |
U | dddd,MMMM dd,yyyy,HH:mm: | UniversalSortable-DateTimePattern(通用可排序模式) |
y,Y | MMMM,yyyy | YearMonthPattern(年月模式) |
DateTimeFormatInfo.InvariantInfo属性得到了默认的只读的DateTimeFormatInfo实例,它与文化无关。你可以创建自定义的模式。要注意到的是InvariantInfo不一定和本地的格式一样。Invariant等于美国格式。另外,如果你向DateTime.Format方法传递的第二个参数是null,DateTimeFormatInfo将会是默认的CurrentInfo。比如
Console.WriteLine(dt.ToString("d", dtfi)); Console.WriteLine(dt.ToString("d", null)); Console.WriteLine()
输出是
06/23/2001 23/06/2001
对比选择InvariantInfo和CurrentInfo的。
DateTimeFormatInfo dtfi; Console.Write("[I]nvariant or [C]urrent Info?: "); if (Console.Read() == ‘I‘) dtfi = DateTimeFormatInfo.InvariantInfo; else dtfi = DateTimeFormatInfo.CurrentInfo; DateTimeFormatInfo dtfi = DateTimeFormatInfo.InvariantInfo; Console.WriteLine(dt.ToString("D", dtfi)); Console.WriteLine(dt.ToString("f", dtfi)); Console.WriteLine(dt.ToString("F", dtfi)); Console.WriteLine(dt.ToString("g", dtfi)); Console.WriteLine(dt.ToString("G", dtfi)); Console.WriteLine(dt.ToString("m", dtfi)); Console.WriteLine(dt.ToString("r", dtfi)); Console.WriteLine(dt.ToString("s", dtfi)); Console.WriteLine(dt.ToString("t", dtfi)); Console.WriteLine(dt.ToString("T", dtfi)); Console.WriteLine(dt.ToString("u", dtfi)); Console.WriteLine(dt.ToString("U", dtfi)); Console.WriteLine(dt.ToString("d", dtfi)); Console.WriteLine(dt.ToString("y", dtfi)); Console.WriteLine(dt.ToString("dd-MMM-yy", dtfi))
输出是
[I]nvariant or [C]urrent Info?: I 01/03/2002 03/01/2002 Thursday, 03 January 2002 Thursday, 03 January 2002 12:55 Thursday, 03 January 2002 12:55:03 01/03/2002 12:55 01/03/2002 12:55:03 January 03 Thu, 03 Jan 2002 12:55:03 GMT 2002-01-03T12:55:03 12:55 12:55:03 2002-01-03 12:55:03Z Thursday, 03 January 2002 12:55:03 01/03/2002 2002 January 03-Jan-02 [I]nvariant or [C]urrent Info?: C 03/01/2002 03/01/2002 03 January 2002 03 January 2002 12:55 03 January 2002 12:55:47 03/01/2002 12:55 03/01/2002 12:55:47 03 January Thu, 03 Jan 2002 12:55:47 GMT 2002-01-03T12:55:47 12:55 12:55:47 2002-01-03 12:55:47Z 03 January 2002 12:55:47 03/01/2002 January 2002 03-Jan-02
/******************************************************************************************
*【Author】:flyingbread
*【Date】:2007年1月18日
*【Notice】:
*1、本文为原创技术文章,首发博客园个人站点(
http://flyingbread.cnblogs.com/