軌道
/
C#
C#
/
課程大綱
/
字串格式化
字串

字串格式化 在 C#

13 個練習

關於 字串格式化

在 C#/.NET 裡,格式化字串的機制多種多樣:從單純把物件串接起來,到呼叫被覆寫的 object.ToString() 方法,再到使用 ICustomFormatter(本練習不涵蓋)都有。

最常見的兩種字串格式化機制是字串內插和 String.Format()。如果情況比較複雜,例如牽涉到多行,也可以用 StringBuilder(cross-ref-tba)類別來組出字串。

使用 ToString()

所有類別和結構都繼承自 System.Object(),而它有一個 ToString() 方法。例如 new DateTime(2019, 5, 23).ToString() 會輸出「05/23/2019 00:00:00」(在採用美國文化的執行緒上,見下文)。在某些情況下,例如字串串接,這個預設的 ToString() 方法可能會被隱式呼叫,"" + new DateTime(2019, 5, 23) 會得到同樣的結果。

除了預設的 ToString() 方法之外,格式化會造成困擾的型別還會提供多載,可以接受格式字串甚至格式提供者。在 BCL(Base Class Library,基底類別庫)中,主要有數字、日期、列舉和 GUID 這幾類。

複合格式

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

在格式被當成某種範本、用在多個運算式裡,或是把格式和要格式化的運算式湊在一起顯得太笨重(例如牽涉到[逐字字串][verbatim-strings])時,Format() 可能是比內插更好的選擇。

這種機制在技術上稱為複合格式。

更完整的字串產生方法清單(會用到_複合格式_的那些)請見這篇文章。

字串內插

內插字串會以 $ 開頭,並包含放在大括號裡的執行階段運算式。格式項目的語法如下:$"{<interpolationExpression>[,<alignment>][:<formatString>]}"。這樣就不需要另外準備一份引數清單。結果在功能上等同於 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

數字和日期都有標準格式和自訂格式。_自訂_和_標準_之間並沒有關鍵性的差別,差別只在你是否有機會用格式字元自行組合出格式字串。這裡的「自訂」和 ICustomFormatter 介面無關,那個介面是在開發你自己的自訂格式器時使用的。

BCL 格式器與格式字串

基底類別庫(BCL)提供 2 種格式器:DateTimeFormatInfo 和 NumberFormatInfo,以及 6 組格式字串。

各種_格式字串_的清單如下:

Enum 和 GUID 的_格式字串_可以歸類為_標準_。雖然 enum 和 GUID 有接受 IFormatProvider 的 ToString() 多載,但它實際上是否有作用並不清楚。

程式庫中試圖為_格式字串_注入一些一致性(除了它們都以字串表示之外)。這種追求一致性表現在標準字串上。實際上,身為開發者,你很少在意標準字串和自訂字串的差別。雖然如果你為自己的類別實作格式器,最好能沿用現有的標準字串(如果你的類別看起來有這個需要),但大體上你可以忽略這個差別。

文化

每個執行緒都有預設的文化 Thread.CurrentThread.CurrentCulture,封裝在 CultureInfo 的執行個體中。執行緒的文化會決定日期和數字預設如何格式化,並反映地區差異,例如英國慣用的日期格式 DD/MM/YYYY 和美國的 MM/DD/YYYY 就不同。

CultureInfo 實作了 IFormatProvider 介面,可以傳給 String.Format() 的某些多載。這可以用來覆寫執行緒的文化。

參考資料

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 字串格式化

練習已鎖定

再解鎖 11 個練習,就能練習 字串格式化