Q:如何把string解析為int?
A:簡單的方法有三種:
string source = "1412";
int result = 0;
// 使用Convert.ToInt32(string value);
result = Convert.ToInt32(source);
// 使用Int32.Parse(string value);
result = Int32.Parse(source);
// 使用Int32.TryParse(string s, out int result);
Int32.TryParse(source, out result);
Q:這三種方法有什麼不同?
A:一個簡單的回答是:
如果解析失敗,Int32.Parse(source)總會拋出異常;Convert.ToInt32(source)在source為null的情況下不會拋出異常而是簡單的返回0給調用方;而Int32.TryParse(source, result)則無論如何都不拋出異常,只會返回true或false來說明解析是否成功,如果解析失敗,調用方將會得到0值。
Q:如果我要解析的字符串的字面數值不是十進制的話,那麼從這些方法中得到的返回值是有問題的。有什麼方法解決?
A:那麼你就需要這些方法的對應重載版本了,一個簡單的方法是使用Convert類的
public static int ToInt32(string value, int fromBase);
其中fromBase的值只能為2、8、10或者16,用於指定進制方式。如果fromBase不是指定的數值或者value不為十進制而又帶有前綴正負號,就會拋出ArgumentException。
string source = "0x1412"; // 這裡的0x(或0X)前綴是可選的。
int result = Convert.ToInt32(source, 16);
當然,你還可以通過為Int32類的
public static int Parse(string s, NumberStyles style);
指定NumberStyles.AllowHexSpecifier或者NumberStyles.HexNumber為第二個參數來解析十六進制字面值的字符串,此時,你需要引用System.Globalization命名空間。
或者使用Int32類的
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out int result);
並指定NumberStyles.AllowHexSpecifier或者NumberStyles.HexNumber為第二個參數,null為第三個參數來解析十六進制字面值的字符串。你當然也應該引用System.Globalization命名空間。
這裡有一點要提醒的是,無論使用Parse或者TryParse方法來解析十六進制,字符串都不能出現0x或0X前綴,否則將會拋出異常。
Q:如果我要把使用科學記數法表示的string轉換為int又該如何呢?
A:你可以通過把NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent(把兩個NunberStyles枚舉進行位運算,其中前者說明可能存在小數點,而後者則說明可能存在科學記數法的指數符號)作為第二個參數傳遞給Int32類的
public static int Parse(string s, NumberStyles style);
或者
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out int result);
如果解析出來的結果與int不兼容的,就要考慮把結果儲存在別的類型了。例如"1.412e2"就應該把解析結果存放到float或者double或者decimal類型的變量裡,當然,你也應該使用與儲存變量相對應的類型的方法來解析:
double result = Double.Parse("1.412e2", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
整個字符串表達式應該沒有任何任何空格,否則將有可能拋出異常。
科學記數法的格式為[{+|-}]m.dddddd{e|E}[{+|-}]xx,可以分解為以下幾種形式:
[-]m.dddddde+xx
下面列舉一些不能正常解析的:
[-]m.dddddde-xx
[-]m.ddddddE+xx
[-]m.ddddddE-xx
"1.412 e3"
"1.412E 3"
"1.412e +3"
"141200E- 2"
Q:如何處理待解析string裡所包含的空格?
A:對於字符串的前綴或後綴空格,你同樣有多種選擇,一般情況下,你可以直接使用String類的
public string Trim();
來取掉頭尾可能包含的空格:
int result = Int32.Parse(textBox1.Text.Trim());
又或者,你使用NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite來告訴Parse或TryParse待解析字符串的頭尾可能包含著空格。
int result = Int32.Parse(textBox1.Text, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite);
如果待解析的字符串使用科學記數法來表示,那麼你可以
int result = Int32.Parse(" 1.412e3 ", NumberStyles.Float);
其中NumberStyles.Float告訴Parse方法待解析的字符串可能前綴或後綴的空格、前綴正負號、(十進制)小數點、科學記數法指數表示等。
Q:如何處理貨幣字符串的解析?
A:你可以通過指定NumberStyles.Currency來告訴Parse或TryParse待解析的字符串是貨幣樣式的。NumberStyles.Currency說明待解析字符串可能包含前綴或後綴空格、前綴正負號、十進制小數點、千分位符號、字面數值可能為整數或小數等:
int result = Int32.Parse(" $1,412 ", NumberStyles.Currency);
但貨幣樣式字符串不能帶有任何十六進制符號。另外,貨幣樣式字符串格式的相關設定以Region and Languages Options(區域與語言選項)裡面的設定為基准。
Q:如果我更改系統的Region and Languages Options(區域與語言選項)裡面的設置,但又希望不按照裡面的設置來解析字符串呢?
A:這個時候就輪到NumberFormatInfo類出場了,這個類能夠讓你無需對系統的設置作任何修改而直接告訴相關的方法如何處理字符串裡的相關符號。
對應上圖,我們通過NumberFormatInfo的相關屬性來設定Customerize Regional Options(自定義區域選項)中Currency(貨幣)選項卡裡的相關設定:
NumberFormatInfo Currency(貨幣) CurrencySymbol Currency symbol(貨幣符號) CurrencyPositivePattern Positive currency format(貨幣正數格式) CurrencyNegativePattern Negative currency format(貨幣符號格式) CurrencyDecimalSeparator Decimal symbol(小數點) CurrencyDecimalDigits No. of digits after decimal(小數數位) CurrencyGroupSeparator Digit grouping symbol(數字分組符號)
其中,Customerize Regional Options(自定義區域選項)中Currency(貨幣)選項卡裡的Digit grouping(數字分組)需要結合NumberFormatInfo的CurrencyGroupSeparator和CurrencyGroupSizes兩個屬性來設定。而NumberFormatInfo的CurrencyPositivePattern和CurrencyNegativePattern屬性的設值是有限制的:
CurrencyPositivePattern Value Associated Pattern 0 $n 1 n$ 2 $ n 3 n $
CurrencyNegativePattern Value Associated Pattern 0 ($n) 1 -$n 2 $-n 3 $n- 4 (n$) 5 -n$ 6 n-$ 7 n$- 8 -n $ 9 -$ n 10 n $- 11 $ n- 12 $ -n 13 n- $ 14 ($ n) 15 (n $)
Q:設置好的NumberFormatInfo的實例應該怎麼使用?
A:NumberFormatInfo是IFormatProvider接口的一個實現,你可以把NumberFormatInfo的實例作為參數傳遞給對應的重載方法。
Q:那麼,Customerize Regional Options(自定義區域選項)中Numbers(數字)選項卡裡的設定是否也能通過NumberFormatInfo的對應屬性來設置?
A:不全是,其中Display leading zeros(零起始顯示)、List separator(列表分隔符)、Measurement system(度量衡系統)這三項沒有;Negative number format(負數格式)需要同時結合使用NumberFormatInfo的NegativeSign、NumberDecimalDigits、NumberDecimalSeparator等來設置;其他的都能在NumberFormatInfo中找到與之對應的屬性。
Q:那麼,Display leading zeros(零起始顯示)、List separator(列表分隔符)、Measurement system(度量衡系統)這三項在哪裡有對應的設置呢?
A:很抱歉,到目前為止我也找不到對應的地方來設置,如果你或者其他人找到了,請務必告訴我。(不過,你可以通過RegionInfo.IsMetric這個只讀屬性來檢測當前系統是否使用Metric(公制)度量系統。)
Q:如果我無法推斷待解析的字符串應該使用哪一個或多個NumberStyles枚舉呢?
A:這種情況一般不會發生,待解析的字符串肯定是有一定的目的或用途的,這些目的或用途就是字符串字面樣式的約束,而NumberStyles枚舉的作用就是說明這種約束的。當然,如果你目前確實無法推斷,那麼你可以使用NumberStyles.Any枚舉。
Q:在具體的編碼過程中,我如何知道應該選擇哪一種方法來解析字符串呢?
A:就我個人來說,我會:
首先,你得清楚你所使用的CLR版本是否提供某種方法的支持,例如,TryParse是.NET 2.0或以上才支持的。
其次,你可以通過方法的重載簽名來選擇,如果你要解析非十進制的字符串,Convert.ToInt32可能是你唯一的選擇,除了十進制和十六進制,你可以用它來解析二進制、八進制,但你不能用Int32.Parse或Int32.TryParse來解釋這些進制的字符串。當然如果是十進制或者十六進制就哪種方法都可以。
另外,如果你需要使用NumberStyles枚舉來告知相關方法待解析的字符串的樣式,那麼Convert.ToInt32就幫不了你了,此時你應該選擇Int32.Parse或者Int32.TryParse相應的重載。
再次,如果你不希望在你的代碼裡處理異常,那麼Int32.TryParse可能是你唯一的選擇,你可能根據它的返回至來判斷解析是否成功,進而決定是否使用解析結果。但如果你希望透過異常機制通知調用方解析失敗,那麼Int32.Parse或者Convert.ToInt32都是不錯的選擇。
最後,選擇准則不可能唯一或者通用的的,你可能會在實踐總結出適合你自己的選擇准則,如果你有更好的選擇方法,請你也告訴我一聲。
Q:在.NET裡面,如果要將string解析為其它的基元類型(Primitive Type)是否也有類似的方法?
A:是的,在.NET裡面,我們為這些基元類型提供了Convert.ToPrimitiveType、PrimitiveType.Parse、PrimitiveType.TryParse(.NET 2.0或以上)方法,用於把string解析成對應的基元類型,當然,你得首先保證待解析的string字面值與對應的基元類型兼容。這些基元類型是(括號中是對應的C#關鍵字):SByte (sbyte), Byte (byte), Int16 (short), UInt16 (ushort), Int32 (int), UInt32 (uint), Int64 (long) , UInt64 (ulong), Char (char), Single (float), Double (double) , Boolean (bool), Decimal (decimal)。另外,.NET也提供了把string解析為DateTime結構的方法,除了有上面提到的三種形式(Convert.ToDateTime、DateTime.Parse、DateTime.TryParse)之外,我們還可以使用DateTime.TryParseExact。所有的這些方法都是大同小異,差別在於對字符串字面值格式(包括其所包含符號)的規定,有興趣的話,你可以參考以下MSDN的文檔或者其他專題資料。