複合格式
.NET 複合格式功能會採用物件清單和複合格式字串作為輸入。 複合格式字串是由混合索引預留位置 (Placeholder) 的固定文字所組成,稱為格式項目。 這些格式項目會對應至清單中的物件。 格式作業產生的結果字串是由原始固定文字所組成,這些固定文字混合了清單中代表物件的字串。
重要
如果您使用的語言及其版本支援,您可以使用「差補字串」,而不使用複合格式字串。 差補字串包含「差補運算式」。 每個插值的運算式會以運算式的值解析,且在字串指派時,包含在結果字串中。 如需詳細資訊,請參閱字串內插補點 (C# 參考) 和字串內插補點 (Visual Basic 參考)。
下列方法支援複合格式功能:
- String.Format,傳回格式化的結果字串。
- StringBuilder.AppendFormat,將格式化的結果字串附加至 StringBuilder 物件。
- Console.WriteLine 方法的部分多載,對主控台顯示格式化的結果字串。
- TextWriter.WriteLine 方法的部分多載,將格式化的結果字串寫入至資料流或檔案。 衍生自 TextWriter 的類別,例如 StreamWriter 和 HtmlTextWriter,也會共用這項功能。
- Debug.WriteLine(String, Object[]),將格式化的訊息輸出至追蹤接聽項。
- Trace.TraceError(String, Object[])、Trace.TraceInformation(String, Object[]) 和 Trace.TraceWarning(String, Object[]) 方法,將格式化的訊息輸出至追蹤接聽項。
- TraceSource.TraceInformation(String, Object[]) 方法,將告知性方法寫入至追蹤接聽項。
複合格式字串
複合格式字串和物件清單會當做支援複合格式功能之方法的引數來使用。 複合格式字串是由零個或更多段與一個或多個格式項目混合的固定文字所組成, 固定文字是您選擇的任何文字,而每個格式項目都會對應到清單內的一個物件或 boxed 結構。 每個物件的字串表示會取代對應的格式項目。
請考量下列 Format 程式碼片段:
string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)
固定的文字為 Name =
和 , hours =
。 格式項目為 {0}
(其索引 0 對應至物件 name
) 及 {1:hh}
(其索引 1 對應至物件 DateTime.Now
)。
格式項目語法
每個格式項目都會使用下列格式,並由下列元件所組成:
{index[,alignment][:formatString]}
成對的大括號 ({
和 }
) 是必要的。
索引元件
強制的 index 元件 (也稱為參數指定名稱) 是用以識別物件清單中對應項目的數字 (從 0 開始)。 也就是說,參數指定名稱為 0
的格式項目會格式化清單中的第一個物件。 參數指定名稱為 1
的格式項目會格式化清單中的第二個物件,依此類推。 下列範例包含四個參數規範 (編號為 0 到 3),以表示小於 10 的質數:
string primes = string.Format("Four prime numbers: {0}, {1}, {2}, {3}",
2, 3, 5, 7);
Console.WriteLine(primes);
// The example displays the following output:
// Four prime numbers: 2, 3, 5, 7
Dim primes As String = String.Format("Four prime numbers: {0}, {1}, {2}, {3}",
2, 3, 5, 7)
Console.WriteLine(primes)
'The example displays the following output
' Four prime numbers 2, 3, 5, 7
多個格式項目可以藉由指定相同參數規範來參考物件清單中的相同項目。 例如,您可以指定複合格式字串 (例如 "0x{0:X} {0:E} {0:N}"
) 來將同一個數值設定成十六進位、科學記號和數字格式,如下列範例所示:
string multiple = string.Format("0x{0:X} {0:E} {0:N}",
Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
// 0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
Int64.MaxValue)
Console.WriteLine(multiple)
'The example displays the following output
' 0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
每個格式項目皆可參考清單內的任何物件。 例如,如果有三個物件,您可以指定複合格式字串 (如 {1} {0} {2}
) 來格式化第二個、第一個和第三個物件。 不是格式項目所參考的物件會被忽略。 如果參數規範指定超出物件清單範圍的項目,則會在執行階段擲回 FormatException。
對齊元件
選擇性 alignment 元件為帶正負號的整數,表示慣用的格式化欄位寬度。 如果 alignment 的值小於格式化字串的長度,則會忽略 alignment 並使用格式化字串的長度當做欄位寬度。 如果 alignment 為正數,欄位中的格式化資料會靠右對齊;如果 alignment 為負數,則會靠左對齊。 如果填補有必要,則會使用泛空白字元 (White Space)。 如果指定了 alignment,則需要逗號。
下列範例會定義兩個陣列,一個包含員工的名稱,另一個包含他們在兩週內的工作時數。 複合格式字串會在 20 個字元的欄位中,將名稱靠左對齊,並且在 5 個字元的欄位中,將其工作時數靠右對齊。 "N1" 標準格式字串也會格式化具有一個小數位數的時數。
string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
"Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
40.333m, 80, 16.75m };
Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");
for (int counter = 0; counter < names.Length; counter++)
Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);
// The example displays the following output:
// Name Hours
//
// Adam 40.0
// Bridgette 6.7
// Carla 40.4
// Daniel 82.0
// Ebenezer 40.3
// Francine 80.0
// George 16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
"Ebenezer", "Francine", "George"}
Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
40.333D, 80, 16.75D}
Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")
For counter = 0 To names.Length - 1
Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next
'The example displays the following output
' Name Hours
'
' Adam 40.0
' Bridgette 6.7
' Carla 40.4
' Daniel 82.0
' Ebenezer 40.3
' Francine 80.0
' George 16.8
格式字串元件
選擇性 formatString 元件是一個格式字串,適用於將格式化的物件類型。 您可以指定:
如果未指定 formatString,則會使用數值、日期和時間或列舉型別的一般 ("G") 格式規範。 如果指定 formatString,則需要冒號。
下表列出 .NET 類別庫中支援一組預先定義之格式字串的型別或型別分類,並提供列出支援之格式字串的文章連結。 字串格式是一種可延伸機制,可讓為所有現有型別定義新的格式字串,以及定義一組應用程式定義型別所支援的格式字串。
如需詳細資訊,請參閱 IFormattable 和 ICustomFormatter 介面主題。
類型或類型分類 | 請參閱 |
---|---|
日期和時間類型 (DateTime、DateTimeOffset) | 標準日期和時間格式字串 自訂日期和時間格式字串 |
列舉類型 (衍生自 System.Enum 的所有類型) | Enumeration Format Strings |
數字類型 (BigInteger、Byte、Decimal、Double、Int16、Int32、Int64、SByte、Single、UInt16、UInt32、UInt64) | 標準數值格式字串 \(部分機器翻譯\) 自訂數值格式字串 |
Guid | Guid.ToString(String) |
TimeSpan | 標準 TimeSpan 格式字串 自訂 TimeSpan 格式字串 |
逸出大括號
左右大括號會被解譯成格式項目的開頭與結尾。 若要顯示字面上的左右大括號,您必須使用逸出序列 (Escape Sequence)。 請在固定文字中指定兩個左邊的大括號 ({{
),以顯示一個左邊的大括號 ({
),或者指定兩個右邊的大括號 (}}
) 來顯示一個右邊的大括號 (}
)。
格式項目的逸出大括號在 .NET 與 .NET Framework 之間會以不同的方式剖析。
.NET
大括號可以在格式項目周圍逸出。 例如,格式項目 {{{0:D}}}
原本是要顯示一個左邊大括號、一個格式化為十進位的數值和一個右邊大括號。 格式項目會以下列方式來解譯:
- 前面兩個左邊大括號 (
{{
) 逸出,產生一個左邊大括號。 - 接下來的三個字元 (
{0:
) 會解譯成格式項目的開頭。 - 下一個字元 (
D
) 會解譯為十進位標準數值格式指定名稱。 - 下一個大括號 (
}
) 會被解譯成格式項目的結尾。 - 最後兩個右大括弧會逸出並產生一個右大括號。
- 最後顯示的結果會是常值字串
{6324}
。
int value = 6324;
string output = string.Format("{{{0:D}}}", value);
Console.WriteLine(output);
// The example displays the following output:
// {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)
Console.WriteLine(output)
'The example displays the following output
' {6324}
.NET Framework
格式項目中的括號會以它們出現的順序依序解譯。 但是不支援解譯巢狀大括號。
解譯逸出括號的方式,可能會造成無法預期的結果。 例如,格式項目 {{{0:D}}}
原本是要顯示一個左邊大括號、一個格式化為十進位的數值和一個右邊大括號。 然而,格式項目會以下列方式來解譯:
- 前面兩個左邊大括號 (
{{
) 逸出,產生一個左邊大括號。 - 接下來的三個字元 (
{0:
) 會解譯成格式項目的開頭。 - 再下一個字元 (
D
可能解譯成十進位 (Decimal) 標準數值格式規範,但後面兩個逸出的右邊大括號 (}}
) 會產生一個大括號。 由於結果字串 (D}
) 並非標準的數值格式規範,因此,結果字串會被解譯成自訂格式字串,表示會顯示成常值字串D}
。 - 最後的大括號 (
}
) 會被解譯成格式項目的結尾。 - 最後顯示的結果會是常值字串
{D}
。 而要進行格式化的數值則不會顯示出來。
int value = 6324;
string output = string.Format("{{{0:D}}}",
value);
Console.WriteLine(output);
// The example displays the following output:
// {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
value)
Console.WriteLine(output)
'The example displays the following output:
' {D}
撰寫程式碼時,能夠避免錯誤解譯逸出大括號和格式項目的方法,就是個別地格式化大括號和格式項目。 也就是說,在第一個格式作業中,顯示常值左大括弧。 在下一個作業中,顯示格式項目的結果,並在最終作業中顯示常值右大括弧。 下列範例將示範這個方法:
int value = 6324;
string output = string.Format("{0}{1:D}{2}",
"{", value, "}");
Console.WriteLine(output);
// The example displays the following output:
// {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
"{", value, "}")
Console.WriteLine(output)
'The example displays the following output:
' {6324}
處理順序
如果對複合格式方法的呼叫包含的 IFormatProvider 引數其值不是 null
,則執行階段會呼叫其 IFormatProvider.GetFormat 方法要求 ICustomFormatter 實作。 如果該方法能夠傳回 ICustomFormatter 實作,則會複合格式方法的呼叫期間快取。
參數清單中每個對應於格式項目的值都會轉換為字串,如下所示:
如果要格式化的值是
null
,則會傳回空字串 String.Empty。如果可以使用 ICustomFormatter 實作,則執行階段會呼叫其 Format 方法。 執行階段會將格式項目的
formatString
值 (若不存在,則為null
) 傳遞給方法。 執行階段也會將 IFormatProvider 實作傳遞至方法。 如果 ICustomFormatter.Format 方法呼叫傳回null
,則會繼續執行到下一個步驟。 否則,會傳回 ICustomFormatter.Format 呼叫的結果。如果值實作 IFormattable 介面,則會呼叫介面的 ToString(String, IFormatProvider) 方法。 如果格式項目中有 formatString 值的話,就會將該值傳遞給方法。 否則,會傳遞
null
。 IFormatProvider 引數的判斷如下:對於數值,如果呼叫具有非 null IFormatProvider 引數的複合格式方法,則執行階段會從其 NumberFormatInfo 方法要求 IFormatProvider.GetFormat 物件。 如果無法提供、如果引數的值為
null
,或者如果複合格式方法沒有 IFormatProvider 參數,則會使用目前文化特性的 NumberFormatInfo 物件。對於日期和時間值,如果呼叫具有非 null IFormatProvider 引數的複合格式方法,則執行階段會從其 DateTimeFormatInfo 方法要求 IFormatProvider.GetFormat 物件。 在下列情況下,會改用目前文化特性的 DateTimeFormatInfo 物件:
- IFormatProvider.GetFormat 方法無法提供 DateTimeFormatInfo 物件。
- 引數的值為
null
。 - 複合格式化方法沒有 IFormatProvider 參數。
對於其他類型的物件,如果呼叫複合格式時包含 IFormatProvider 引數,它的值會直接傳遞至 IFormattable.ToString 實作。 否則會傳遞
null
至 IFormattable.ToString 實作。
呼叫類型的無參數
ToString
方法,該方法會覆寫 Object.ToString() 或繼承其基底類別的行為。 在這種情況下,會忽略formatString
元件在格式項目中指定的格式字串 (如果有的話)。
對齊會在已經執行前面的步驟之後套用。
程式碼範例
下列範例顯示一個使用複合格式建立的字串,以及另一個使用物件的 ToString
方法建立的字串。 這兩個類型的格式化產生相等結果。
string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")
假設目前日期是五月的星期四,前面範例中兩個字串的值在美國英文文化特性中都是 Thursday May
。
Console.WriteLine 會公開與 String.Format 相同的功能。 這兩種方法唯一的差別在於,String.Format 會以字串形式傳回結果,而 Console.WriteLine 則會將結果寫入至與 Console 物件關聯的輸出資料流。 下列範例使用 Console.WriteLine 方法,將 myNumber
的值格式化為貨幣值:
int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);
// The example displays the following output
// if en-US is the current culture:
// $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)
'The example displays the following output
'if en-US Is the current culture:
' $100.00
下列範例示範多個物件的格式化,其中包括以兩種不同方式來格式化一個物件:
string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
myName, DateTime.Now));
// Depending on the current time, the example displays output like the following:
// Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
' Name = Fred, hours = 11, minutes = 30
下列範例示範格式設定中的對齊用法。 格式化的引數會放在兩個垂直線 (|
) 字元之間以強調所產生的對齊。
string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;
string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name = |{0,10}|", lastName);
string formatPrice = string.Format("Price = |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();
formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name = |{0,-10}|", lastName);
formatPrice = string.Format("Price = |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
// The example displays the following output on a system whose current
// culture is en-US:
// First Name = | Fred|
// Last Name = | Opals|
// Price = | $100.00|
//
// First Name = |Fred |
// Last Name = |Opals |
// Price = |$100.00 |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100
Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name = |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price = |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()
formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name = |{0,-10}|", lastName)
formatPrice = String.Format("Price = |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
'The example displays the following output on a system whose current
'culture Is en-US:
' First Name = | Fred|
' Last Name = | Opals|
' Price = | $100.00|
'
' First Name = |Fred |
' Last Name = |Opals |
' Price = |$100.00 |