如何把string解析為int?[C#]
How to Parse a string to an int? [C#]
Writen by Allen Lee
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的文檔或者其他專題資料。