.NET 中的數字格式化,日期格式化
關鍵詞: 格式化,字符串,
格式
基本內容是:可以在 Console.WriteLine(以及 String.Format,它被 Console.WriteLine 調用)中的格式字符串內的括號中放入非索引數字的內容。格式規範的完整形式如下:
{index [, width][:formatstring]}
其中,index 是此格式程序引用的格式字符串之後的參數,從零開始計數;width(如果有的話)是要設置格式的字段的寬度(以空格計)。width 取正數表示結果右對齊,取負數則意味着數字在字段中左對齊。(請參閱下面的前兩個示例。)
formatstring 是可選項,其中包含有關設置類型格式的格式說明。如果對象實現 IFormattable,formatstring 就會傳遞給對象的 Format 方法(在 Beta 2 和後續版本中,該方法的簽名變爲 ToString(string, IFormatProvider),但功能不變)。如果對象不實現 IFormattable,就會調用 Object.ToString(),而忽略 formatstring。
另請注意,在 Beta 1 中不區分當前語言的 ToString 在 Beta 2 和後續版本中“將”區分語言。例如,對於用“.”分隔千位,用“,”分隔小數的國家,1,234.56 將會格式化成 1.234,56。如果您需要結果無論在什麼語言下都是一樣的,就請使用 CultureInfo.InvariantCulture 作爲語言。
若要獲取有關格式的完整信息,請查閱“.NET 框架開發人員指南”中的格式概述(英文)。
數字格式
請注意,數字的格式是區分語言的:分隔符以及分隔符之間的空格,還有貨幣符號,都是由語言決定的 — 默認情況下,是您計算機上的默認語言。默認語言與執行線程相關,可以通過 Thread.CurrentThread.CurrentCulture 瞭解和設置語言。有幾種方法,可以不必僅爲一種給定的格式操作就立即更改語言。
內置類型的字母格式
有一種格式命令以單個字母開頭,表示下列設置:
G—常規,E 或 F 中較短的
F—浮點數,常規表示法
E—用 E 表示法表示的浮點數(其中,E 代表 10 的次冪)
N—帶有分隔符的浮點數(在美國爲逗號)
C—貨幣,帶有貨幣符號和分隔符(在美國爲逗號)
D—十進制數,僅用於整型
X—十六進制數,僅用於整型
字母可以後跟一個數字,根據字母的不同,該數字可以表示總位數、有效位數或小數點後面的位數。
下面是字母格式的一些示例:
double pi = Math.PI;
double p0 = pi * 10000;
int i = 123;
Console.WriteLine("浮點格式,無分隔符(逗號)");
Console.WriteLine("pi, Left {0, -25}", pi); // 3.1415926535897931
Console.WriteLine("p0, Rt. {0, 25}", p0); // 3.1415926535897931
Console.WriteLine("pi, E {0, 25:E}", pi); // 3.1416E+000
Console.WriteLine("使用 E 和 F 格式,小數點後保留 n(此處爲 4)位");
Console.WriteLine("pi, E4 {0, 25:E4}", pi); // 3.1416E+000
Console.WriteLine("pi, F4 {0, 25:F4}", pi); // 3.1416
Console.WriteLine("使用 G 格式,保留 4 位有效數字——如果需要請使用 E 格式");
Console.WriteLine("pi, G4 {0, 25:G4}", pi); // 3.142
Console.WriteLine("p0, G4 {0, 25:G4}", p0); // 3.142E4
Console.WriteLine("N 和 C 格式帶有逗號(分隔符)," +
"默認小數點後保留兩位,四捨五入。");
Console.WriteLine("p0, N {0, 25:N}", p0); // 31,415.93
Console.WriteLine("p0, N4 {0, 25:N4}", p0); // 31,415.9265
Console.WriteLine("p0, C {0,25:C}", pi); // $3.14
Console.WriteLine("D 和 X 格式僅用於整型," +
"非整型將產生格式異常——X 指十六進制");
Console.WriteLine("i, D {0, 25:D}", i ); // 123
Console.WriteLine("i, D7 {0, 25:D7}", i ); // 0000123
Console.WriteLine("i, X {0, 25:X}", i ); // 7B
Console.WriteLine("i, X8 {0, 25:X8}", i ); // 0000007B
圖片格式
與字母格式不同,formatstring 可以包含“圖片格式”。下面是從代碼中摘錄的幾個實例。(這類似於 Basic 中的“Print Using”語句。)圖片格式功能甚至包括以不同方式設置負數、正數和零的格式的能力。還有幾個圖片格式功能,下面的示例中未包括在內。有關詳細信息,請參閱“.NET 框架開發人員指南”或文檔中的主題圖片格式數字串(英文)。
在下例中您將注意到,好心的博士既使用了“#”字符,又使用了“0”字符。如果相應的數字是前導零或尾隨零,“#”字符就會替換爲空值。無論相應數字的值如何,“0”字符都會被替換爲零字符 — 因此,數字將會被零填補。句號(如果有的話)表示小數分隔符的位置。
那麼,爲什麼要同時使用這些字母,比如“###0.##”? 如果要設置格式的值恰好爲零,“#” 圖片字符就被替換爲“無”(連零字符也不是)。您可能“總是”希望在小數點的左邊至少有一個“0”,否則,如果值爲零,字段就沒有輸出。換言之,僅包含“#”字符,一個“0”也沒有的格式常被認爲是一個編程錯誤。
逗號有兩種用法:如果一個逗號或一組逗號緊跟在句號的左邊(或者沒有句號時在結尾),它們就會告訴格式化程序分隔 10 ** (3 * n) 所顯示的數字,其中,n 是逗號的個數。換言之,數字按千位、百萬位、十億位等分隔。
如果逗號的右側至少有一個“0”或“#”佔位符,它就會告訴格式化程序在各數位組之間放置適當的組分隔符字符(在美國爲逗號。)(在美國,每三個數位算一組。)
可以設置百分比的格式,方法是在圖片中放入“%”。“%”將在指定的位置顯示,在顯示前數字將被乘以 100(這樣,0.28 就變成了 28%)。
如果希望將圖片格式用於指數表示法,可以指定“e”或“E”後跟加號或減號,再後跟任意個零,比如“E+00”或“e-000”。如果使用“e”,則顯示小寫“e” 。如果使用“E”,則顯示大寫“E” 。如果使用加號,則指數的符號總是出現。如果使用減號,則符號只有在指數爲負數時纔會顯示。(Beta 1 版在處理“-”時有問題,該符號會導致負號總是出現。)
根據要設置格式的數字的符號,還有一個條件格式。在格式字符串中僅包含兩個或三個獨立的格式,它們由分號分隔。如果有兩個格式,則第一個將用於非負數,第二個用於負數。如果有三個格式,則第一個將用於正數,第二個用於負數,第三個用於零。
可以在格式字符串中包含文字字符。如果所需的字符具有特殊意義,請在其前面使用反斜槓符號,使其“轉義”。例如,如果希望在不乘以 100 的情況下顯示百分比符號,就可以在數字前面使用反斜槓(在 C++ 和 C# 中必須使用兩個反斜槓),比如“#0.##//%”
。(如果正在使用 C#,就可以使用極酷的逐字字符串文字,比如@"#0.##/%"。
)或者,也可以將字符串放入單引號或雙引號中,以避免將其字符解釋爲格式命令。在 Beta 2 及更高版本中,可以通過使用雙括號,從而在格式字符串中包含文字括號。
下面是有關圖片格式的一些示例:
long m34 = 34000000; // 34,000,000
Console.WriteLine("幾種圖片格式");
Console.WriteLine("如果沒有數位,0 將打印 0;" +
"諸如 i: 的文字總是打印");
Console.WriteLine("/t句點代表小數分隔符的位置");
Console.WriteLine("i, i: 0000.0 {0, 10:i: 0000.0}", i); //
i:0123.0
Console.WriteLine("如果沒有有效數字 # 將不顯示," +
"逗號意味着放入分隔符");
Console.WriteLine("請確保在數字圖片中至少使用一個 0。");
Console.WriteLine("p0, ##,##0.# {0, 10:##,##0.#}",-p0); // -31,415.9
Console.WriteLine("m34, 0,, {0, 10:0,, 百萬}", m34); // 34 百萬
Console.WriteLine("p0, #0.#E+00 {0, 10:#0.#E+00}", p0); // 31.4E+03
Console.WriteLine("% 乘以 100 並打印百分號");
Console.WriteLine("pi, ###0.##% {0, 10:###0.##%}", pi); // 314.16%
Console.WriteLine("因爲 // 而沒有進行乘法運算" +
"(注意:兩個反斜線!)");
Console.WriteLine("pi, ###0.##////% {0, 10:###0.##//%}", pi); // 3.14%
Console.WriteLine("與 C# 的逐字字符串相同");
Console.WriteLine(@"pi, ###0.##//% {0, 10:###0.##/%}", pi); // 3.14%
Console.WriteLine("10, '#'#0 {0, 10:'#'#0}", 10); // #10
Console.WriteLine("基於符號的條件格式");
Console.WriteLine("如果是 0 或正數打印 #,如果是負數打印 (#)");
Console.WriteLine("-5 0;(0) {0, 10:0;(0)}", -5); // (5)
Console.WriteLine("如果是正數打印 #,如果是負數打印 -#,如果是 0 打印 zip");
Console.WriteLine(" 0 0;-0;zip {0, 10:0;-0;zip}", 0); // zip
如您所見,格式功能非常強大。
格式的工作方式
文檔中的示例對所傳遞的對象類型的變量調用 Format 方法。對這些 Format 方法僅傳遞格式規範的 formatstring 部分,而不傳遞 index 和 width。(在 Beta 2 中,對 Format 的調用將改爲對 ToString 的調用。)
index 和 width 由 String.Format(它被 Console.Write 和 Console.WriteLine 調用)使用,以獲得調用 Format 的正確對象以及將該調用的結果左或右對齊。(順便說一下,如果要設置格式的對象不實現 IFormattable(並因此調用 Format 方法),String.Format 將調用對象的 ToString() 方法,而忽略 formatstring。)
換言之,Console.WriteLine 調用 String.Format,傳遞向它傳遞的所有參數。String.Format 分析字符串,查找“{”字符。找到該字符後,它將分析子字符串直到第一個“}”爲止,以確定 index 數、width 和 formatstring。然後,它按照 index 訪問相應的參數,並調用其 Format 方法,傳遞“{}”段中的 formatstring 部分。(如果參數對象不實現 IFormattable,則被調用的是 ToString。)
無論是實現還是不實現,都會返回一個字符串,並且 String.Format 在繼續分析格式字符串之前會將其與結果字符串連接。之後,String.Format 將生成的帶格式字符串返回給 Console.WriteLine,由 Console.WriteLine 進行顯示。
對於 Beta 2 及更高版本,對象的 Format 方法(它是 IFormattable 中的 Format 方法)被 ToString 所替代,ToString 獲取一個格式字符串和一個 IFormatProvider(或 null)。但 String.Format 仍存在,因此這些調用將不改變。
自定義格式
您自己也可以編寫格式化程序,用於自己的類型或作爲內置類型的自定義格式化程序,如“.NET 框架開發人員指南”中的自定義 Format 方法所說明的那樣。如果編寫內置類型的自定義格式化程序,就不能從 Console.WriteLine 中使用它,但可以通過調用 String.Format 的重載而使用它,String.Format 的重載將採用 IServiceObjectProvider(在 beta 2 及更高版本中稱爲 IFormatProvider)作爲參數。
日期和時間格式
您將記起,有一個叫做 DateTime 的類,用於保存日期和時間。像您所猜想的那樣,有大量方法可供設置 DateTime 對象的格式:僅日期、僅時間、世界時或本地時、若干種日/月/年順序,甚至可分類。日期和時間格式是區分語言的。
還可以使用自定義格式字符串來設置 DateTime 對象的格式。這種字符串將包含由某些字母組成的區分大小寫的子字符串,以表示日期和時間的各個不同部分,如星期幾、幾號、月份、年份、紀元、小時、分鐘、秒或時區。這些部分中有許多具有多種格式,例如,M 是沒有前導零的數字月份,MM 是有前導零的數字月份,MMM 是三個字母的月份縮寫,MMMM 是所在國家語言對應的完整月份名稱的拼寫。在“.NET 框架參考”中可以找到自定義和標準格式字符的完整列表。
下面是有關日期和時間格式的一個示例:
Console.WriteLine("標準格式");
// 後面的“分析”中會有更多信息
DateTime dt = DateTime.Parse("2001 年 1 月 1 日,12:01:00am");
Console.WriteLine("d: {0:d}", dt); // 1/1/2001
Console.WriteLine("D: {0:D}", dt); // 2001 年 1 月 1 日,星期一
Console.WriteLine("f: {0:f}", dt); // 2001 年 1 月 1 日,星期一 12:01 AM
Console.Write("F: {0:F}", dt); // 2001 年 1 月 1 日,星期一 12:01:00 AM
Console.WriteLine();
Console.WriteLine("g: {0:g}", dt); // 1/1/2001 12:01 AM
Console.WriteLine("G: {0:G}", dt); // 1/1/2001 12:01:00 AM
Console.WriteLine("M/m: {0:M}", dt); // 2001 年 1 月
Console.WriteLine("R/r: {0:R}", dt); // 2001 年 1 月 1 日,星期一 08:01:00 GMT
Console.WriteLine("s: {0:s}", dt); // 2001-01-01T00:01:00
Console.WriteLine("t: {0:t}", dt); // 12:01 AM
Console.WriteLine("T: {0:T}", dt); // 12:01:00 AM
Console.WriteLine("u: {0:u}", dt); // 2001-01-01 08:01:00Z
Console.Write("U: {0:U}", dt); // 2001 年 1 月 1 日,星期一 8:01:00 AM
Console.WriteLine();
Console.WriteLine("Y/y: {0:Y}", dt); // 2001 年 1 月
Console.WriteLine("自定義格式");
// 對作爲格式使用的字符必須“轉義”—此處爲 t 和 z
// 同時使用引號(在文字字符串中)和反斜槓
Console.WriteLine(@"dddd, dd MMMM yyyy"" at ""HH:mm:ss in /zone zzz:");
Console.WriteLine(@"{0:dddd, dd MMMM yyyy"" at ""HH:mm:ss in /zone zzz}",
dt);
// 2001 年 1 月 1 日,星期一 00:01:00 於時區 -08:00
http://www.microsoft.com/china/MSDN/library/archives/library/welcome/dsmsdn/drguinet03292001.asp
程序:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
double pi = Math.PI;
double p0 = pi * 10000;
int i = 123;
long m34 = 34000000; // 34,000,000
Console.WriteLine("幾種圖片格式");
Console.WriteLine("如果沒有數位,0 將打印 0;" +
"諸如 i: 的文字總是打印");
Console.WriteLine("/t句點代表小數分隔符的位置");
Console.WriteLine("i, i: 0000.0 {0, 10:i: 0000.0}", i); // i:0123.0
Console.WriteLine("如果沒有有效數字 # 將不顯示," +
"逗號意味着放入分隔符");
Console.WriteLine("請確保在數字圖片中至少使用一個 0。");
Console.WriteLine("p0, ##,##0.# {0, 10:##,##0.#}", -p0); // -31,415.9
Console.WriteLine("m34, 0,, {0, 10:0,, 百萬}", m34); // 34 百萬
Console.WriteLine("p0, #0.#E+00 {0, 10:#0.#E+00}", p0); // 31.4E+03
Console.WriteLine("% 乘以 100 並打印百分號");
Console.WriteLine("pi, ###0.##% {0, 10:###0.##%}", pi); // 314.16%
Console.WriteLine("pi, ###0.##% {0, 10:#######0.##%}", pi); // 314.16%
Console.WriteLine("因爲 // 而沒有進行乘法運算" +
"(注意:兩個反斜線!)");
Console.WriteLine("pi, ###0.##////% {0, 10:###0.##//%}", pi); // 3.14%
Console.WriteLine("與 C# 的逐字字符串相同");
Console.WriteLine(@"pi, ###0.##//% {0, 10:###0.##/%}", pi); // 3.14%
Console.WriteLine("10, '#'#0 {0, 10:'#'#0}", 10); // #10
Console.WriteLine("10, '#'#0 {0, 10:##0}", 10); // 10
Console.WriteLine("基於符號的條件格式");
Console.WriteLine("如果是 0 或正數打印 #,如果是負數打印 (#)");
Console.WriteLine("-5 0;(0) {0, 10:0;(0)}", -5); // (5)
Console.WriteLine("如果是正數打印 #,如果是負數打印 -#,如果是 0 打印 zip");
Console.WriteLine(" 0 0;-0;zip {0, 10:0;-0;zip}", 0); // zip
Console.ReadLine();
}
}