第 7 講:數(shù)據(jù)類型(四):格式化輸出
格式化輸出(Formatted Output)是為了保證數(shù)據(jù)顯示和呈現(xiàn)有序和控制顯示規(guī)范的一種模式。在我們之前的輸出內(nèi)容里,我們完全不必需要顯示任何額外的東西,因?yàn)楸旧盹@示出來(lái)就已經(jīng)達(dá)到了目的。
那么,如果我們要顯示一個(gè)表格的話,單純的字符串就沒辦法控制得那么好了。下面我們來(lái)介紹這種控制輸出格式的語(yǔ)法規(guī)則和用法。
Part 1 填充(Padding)
填充分兩種:空格填充和非空格填充,所以分兩部分介紹。
1-1 空格填充
我們?cè)谥帮@示一個(gè)數(shù)字的時(shí)候,我們通過(guò) Console.WriteLine
方法來(lái)顯示。而如果要把數(shù)值嵌入到字符串的指定位置的時(shí)候,我們用的是一個(gè)叫做占位符的東西,寫成一個(gè)大括號(hào),里面是編號(hào)。
那么,如果我們要控制顯示的數(shù)據(jù)的前后空格個(gè)數(shù),怎么辦呢?舉個(gè)例子。假設(shè)我要輸出表格,表格假設(shè)為兩列,而第一列放數(shù)字信息,且這一列的寬度占據(jù) 8 個(gè)數(shù)字字符的位置:
比如說(shuō)這樣。為了保證顯示的空格后面補(bǔ)充 7 個(gè)空格(使得數(shù)字一共占 8 個(gè)字符位置),我們可以這么寫:
填充空格(Space Padding)的東西。
我們推廣一下占位符的語(yǔ)法。我們?cè)谡嘉环木幪?hào)后添加逗號(hào),然后增加一個(gè)整數(shù),用來(lái)表示這個(gè)位置顯示的數(shù)據(jù),左側(cè)或右側(cè)補(bǔ)充一定數(shù)量的空格來(lái)保證整體數(shù)字的顯示。
舉個(gè)例子,我們使用語(yǔ)法 {0,8}
表示,這個(gè)占位符的編號(hào)是 0(即第一個(gè)替換數(shù)據(jù)),且它在輸出的時(shí)候占據(jù) 8 個(gè)字符的位置;如果數(shù)據(jù)不夠長(zhǎng)(比如前文表格里的那個(gè)數(shù)字,只有一位數(shù)),那么就會(huì)在左側(cè)補(bǔ)充空格。
如果逗號(hào)后面這個(gè)數(shù)字為負(fù)數(shù)的話,就表示在右側(cè)補(bǔ)充空格來(lái)保證數(shù)據(jù)占多少個(gè)字符的位置。比如說(shuō):
這兩個(gè)數(shù)據(jù)的顯示結(jié)果分別是

總結(jié)一下:
正整數(shù)表示在左邊補(bǔ)充空格達(dá)到指定寬度;
負(fù)整數(shù)表示在右邊補(bǔ)充空格達(dá)到指定寬度。
當(dāng)然,這個(gè)占位符同樣可以適用于浮點(diǎn)數(shù)類型數(shù)據(jù)。只是,浮點(diǎn)數(shù)的小數(shù)點(diǎn)、整數(shù)部分、小數(shù)部分全部都算在格式排版的范圍內(nèi)。比如 3.5 是由整數(shù)部分 3、小數(shù)點(diǎn)和小數(shù)部分 5 構(gòu)成的。整數(shù)部分占一個(gè)字符、小數(shù)點(diǎn)占一個(gè)字符、小數(shù)部分占一個(gè)字符,所以 3.5 是算三個(gè)字符位置。因此,如果對(duì)小數(shù)使用這個(gè)占位符補(bǔ)充空格的話,一定要注意字符的寬度的補(bǔ)充空格數(shù)量。
順帶一提,如果數(shù)據(jù)超出指定寬度的范圍的話,那么這個(gè)指定的寬度就沒有意義了。比如說(shuō)一個(gè)浮點(diǎn)數(shù) 123.456 一共占據(jù) 7 個(gè)字符的位置,但是用
{0,6}
作為占位符的話,輸出寬度顯然是不夠的,所以這個(gè)占位符里的指定寬度 6 是無(wú)效的。所以這樣一來(lái),占位符就等價(jià)于{0}
。
1-2 非空格填充
當(dāng)然,空格可以用來(lái)填充,但是我們有時(shí)候也可以用別的符號(hào)來(lái)作為填充對(duì)象,但占位符的填充行為只能是使用空格,因此占位符只能做空格的填充。如果要?jiǎng)e的符號(hào),我們這里要用別的辦法了。
C# 里有一個(gè)方法叫做 string.PadLeft
或者 string.PadRight
。這兩個(gè)方法專門用來(lái)填充指定的內(nèi)容(不一定是空格)。
我們使用 .PadLeft
或 .PadRight
.PadRight(8, ' ')
,這個(gè) 8 和前面占位符里的指定寬度(-8)是一個(gè)邏輯(指定寬度里是可以寫負(fù)整數(shù)的,但是這里用 PadRight
的時(shí)候,因?yàn)?PadLeft
是左側(cè)補(bǔ)充字符,PadRight
在右側(cè)補(bǔ)充字符,所以用 PadRight
就會(huì)自動(dòng)在右側(cè)補(bǔ)充字符,因此不需要負(fù)號(hào));而逗號(hào)后面的這個(gè) ' '
是空格字符,這表示補(bǔ)充的時(shí)候用空格來(lái)補(bǔ)充。所以,上面這種寫法完全和前面占位符寫法 {0,-8}
是等價(jià)的。
但是,你也可以用別的填充字符。比如說(shuō):
此時(shí)我們用的 PadLeft
就表示在左側(cè)補(bǔ)充。逗號(hào)后面寫的是 '0'
00000001
。這是一個(gè)相當(dāng)方便的填充方式。
唯一一點(diǎn)需要注意的是,這里用的 .PadLeft
和 .PadRight
,小數(shù)點(diǎn)左側(cè)都必須是字符串(變量也好,字面量也好,但不能是別的東西)。
Part 2 說(shuō)明符(Specifier)
前文的排版填充空格或非空格的內(nèi)容其實(shí)不太難,但是語(yǔ)法嚴(yán)謹(jǐn)導(dǎo)致很多時(shí)候初學(xué)它們會(huì)很容易記不住它們。沒有關(guān)系,這畢竟不是考試,所以不要擔(dān)心用不來(lái)。只要你記不住,還可以回來(lái)翻文檔,也可以網(wǎng)上查資料。
下面這個(gè)內(nèi)容,是用來(lái)轉(zhuǎn)換呈現(xiàn)數(shù)據(jù)模型的。在 C# 里,除了我們可以顯示整數(shù)、小數(shù)以外,它還提供了顯示貨幣、百分比等等模型。顯然貨幣并不是一種數(shù)據(jù)類型,但用來(lái)把一個(gè)數(shù)值作為呈現(xiàn)對(duì)象的話,就需要這樣的說(shuō)明符號(hào)來(lái)表達(dá)出我到底希望它顯示成啥樣。
比如說(shuō),我想把 123
這個(gè)數(shù)字顯示成貨幣表達(dá)式,而因?yàn)樨泿挪⒉皇菙?shù)據(jù)類型,因此我們沒有辦法通過(guò)變量賦值和字面量的方式來(lái)把 123 給到一個(gè)“貨幣類型”的變量上去。因此,這里只能靠呈現(xiàn)來(lái)完成任務(wù)。
我們使用冒號(hào) :
,和一個(gè)字母 C
(或小寫字母 c
¥123.00
。
貨幣顯示的話,不同國(guó)家使用這個(gè)方法產(chǎn)生的結(jié)果是有偏差的。比如在中國(guó),這段輸出就是顯示人民幣的結(jié)果;而其它國(guó)家可能是別的貨幣符號(hào),比如說(shuō)英鎊(
£
)、美元($
)等等。電腦會(huì)自動(dòng)抉擇符號(hào)選取,因此非常方便。
說(shuō)明符有如下的一些(不全,用不上的就不介紹了):

其中,只有 D
和 X
只支持整數(shù),其它的則整數(shù)、小數(shù)均可。所謂的“只支持整數(shù)”,其實(shí)就是說(shuō),占位符替換的變量(或字面量)必須得是一個(gè)整數(shù)。不論它是短整數(shù)、長(zhǎng)整數(shù)、甚至無(wú)符號(hào)整數(shù)等等,它們起碼用來(lái)表示整數(shù),所以它們都屬于整數(shù)類型。但是,浮點(diǎn)數(shù)就不行。如果嘗試把浮點(diǎn)數(shù)用類似 {0:D}
的語(yǔ)法的話,就會(huì)直接在運(yùn)行程序的時(shí)候看到嚴(yán)重的錯(cuò)誤信息提示。
另外,D
后是可以跟上一個(gè)正整數(shù)的,這樣就可以保證顯示的數(shù)據(jù)的左側(cè)補(bǔ)充一定數(shù)量的字符 0。之前我們用 PadLeft
D8
,就表示用整數(shù)形式顯示,且填充 0 到數(shù)字之前以保證顯示寬度為 8 個(gè)字符。
當(dāng)然,別的說(shuō)明符后也可以加數(shù)字,比如貨幣類型后加數(shù)字表示顯示到小數(shù)位后多少位;不過(guò)這里用不上其它的,就不用多說(shuō)了:說(shuō)多了反而記不住。
Part 3 混用說(shuō)明符和寬度指定
如果我們既想要指定寬度,又想要指定說(shuō)明符的話,我們就需要都寫上。因此,C# 的語(yǔ)法是這樣的:
比如這個(gè)例子里,{0,-28:C2}
就是在說(shuō),這里顯示的數(shù)據(jù)是第一個(gè)代替數(shù)值 amount1
,占 28 個(gè)字符寬度(不夠長(zhǎng)度就在右邊填充空格);C2
表示顯示貨幣表達(dá)式,且顯示兩位小數(shù);同理后面的 {1,14:C2}
是一樣的用法。
Part 4 顯示數(shù)字的通配符
除了使用說(shuō)明符 D
(或小寫 d
)來(lái)顯示數(shù)字,我們還可以使用通配符表達(dá)式來(lái)顯示一個(gè)數(shù)字。這里說(shuō)的數(shù)字既包含整數(shù)又包含浮點(diǎn)數(shù)。
如果前面的這些格式并不能滿足你自定義顯示一種數(shù)據(jù)模型的話,那么這一節(jié)的內(nèi)容會(huì)比較靈活。
我們使用數(shù)字 0 來(lái)表示一個(gè)顯示的數(shù)位(如果這個(gè)位置上沒有數(shù)字,則故意顯示一個(gè)字符 0 占位)。比如說(shuō)
顯然 12 不夠三個(gè)數(shù)位的,所以 {0:000}
里的 000
保證顯示三個(gè)數(shù)位,最高位用 0 填充,即顯示結(jié)果是 012。
這個(gè)用法前面已經(jīng)有一樣的了。所以這里就得看你用
PadLeft
方便一些,還是D3
方便一些,還是這個(gè)000
PadLeft
需要接的是字符串而不是整數(shù),稍微麻煩一點(diǎn)。
其它還有逗號(hào)(三位一組分隔符)、逗點(diǎn)組合(縮小 1000 倍數(shù)據(jù))、井號(hào)(數(shù)字)、百分號(hào)(百分比數(shù)據(jù))等等通配符,但這里就不說(shuō)明了。