來看一個比較長的數字在.NET下的輸出:
//+ using System.Globalization;
//+ using System.Threading;
//把當前線程的CultureInfo改成中文-中國"
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("zh-cn");
decimal m = 987654321;
Console.WriteLine(m);
Console.WriteLine(m.ToString("N"));
Console.WriteLine(m.ToString("C"));
輸出:
987654321
987,654,321.00
¥987,654,321.00
顯然第一種輸出最不可取,沒有分隔字元,太難分辨數位了。
但是後面的輸出雖然用了格式化輸出符,並且當前線程的CultureInfo也是“中文-中國”,但是.NET Framework還是會按照英文數位模式進行輸出(除了貨幣符號是中文的¥)。這是為了“國際化”?
管它什麼化,反正這個數字中國人讀起來肯定不爽。因為我們從小學習數字讀法都是以4個位做分隔:個十百千,萬十萬百萬千萬,億。九個數正好是九億開始。而這個數是以3位做分隔,我們還是得數位元。這個數其實還是為熟悉英語的人服務的,他們可以很好得讀出來:nine hundred and eighty-seven million, six hundred and fifty-four thousand, three hundred and twenty-one。人家直接把兩個逗號讀成million和thousand就可以了。
改進方法就是自訂CultureInfo(事實上是在自訂一個IFormatProvider,後面會講),設定的對象就是CultureInfo的NumberFormatInfo。
NumberFormatInfo中的GroupSizes和GroupSeparator對應數位數位分隔長度和分隔字元。另外NumberFormatInfo中的屬性的設定根據Currency,Number和Percentage分別對應輸出時的C,G和P格式化標識符。(當直接調用ToString沒有任何參數相當於G參數)。
下面程式執行個體中就以CurrencyGroupSizes,CurrencyGroupSeparator和NumberGroupSizes,NumberGroupSeparator做樣本,讀者可以舉一反三。當然NumberFormatInfo不限於這些屬性,推薦讀者閱讀下MSDN做延伸:http://msdn.microsoft.com/zh-cn/library/system.globalization.numberformatinfo
我們的目的很簡單,把3位分隔改成4位分隔,並且把分隔字元逗號替換成空格。(因為有些人會把逗號錯看成小數點)
代碼:
//+ using System.Globalization;
//+ using System.Threading;
//修改CultureInfo的NumberFormatInfo
var culture = (CultureInfo)CultureInfo.GetCultureInfo("zh-cn").Clone();
culture.NumberFormat.NumberGroupSizes =
culture.NumberFormat.CurrencyGroupSizes = new int[] { 4 };
culture.NumberFormat.NumberGroupSeparator =
culture.NumberFormat.CurrencyGroupSeparator = " ";
//設定成當前線程的CultureInfo
Thread.CurrentThread.CurrentCulture = culture;
decimal m = 987654321;
Console.WriteLine(m.ToString("N"));
Console.WriteLine(m.ToString("C"));
輸出:
9 8765 4321.00
¥9 8765 4321.00
很好!這下什麼數字一目瞭然了。九億 八千七百六十五萬 四千三百二十一!
還有一個問題,如果你不方便修改線程的CultureInfo的話(或許你的程式依賴當前作業系統的CultureInfo不能隨意修改,因為一旦修改了線程的CultureInfo,所有輸出都會以這種方式的)。其實細細學.NET的話,你會發現CultureInfo和NumberFormatInfo都繼承IFormatProvider介面,同時.NET中的字元輸出方法(ToString和String.Format方法)都提供自訂的IFormatProvider的。
代碼:
//+ using System.Globalization;
//修改CultureInfo的NumberFormatInfo
var culture = (CultureInfo)CultureInfo.GetCultureInfo("zh-cn").Clone();
culture.NumberFormat.NumberGroupSizes =
culture.NumberFormat.CurrencyGroupSizes = new int[] { 4 };
culture.NumberFormat.NumberGroupSeparator =
culture.NumberFormat.CurrencyGroupSeparator = " ";
decimal m = 987654321;
//使用當前線程的CultureInfo
Console.WriteLine(m.ToString("N"));
//使用CultureInfo作為IFormatProvider
Console.WriteLine(m.ToString("N", culture));
//使用NumberFormatInfo作為IFormatProvider
Console.WriteLine(m.ToString("N", culture.NumberFormat));
//String.Format方法也有IFormatProvider
Console.WriteLine(String.Format(culture, "{0:N}", m));
輸出:
987,654,321.00
9 8765 4321.00
9 8765 4321.00
9 8765 4321.00