如何把string解析为int?[C#]

如何把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.ToPrimitiveTypePrimitiveType.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的文档或者其他专题资料。

 

posted @ 2004-11-16 09:00 Allen Lee 阅读(29054) 评论(38) 编辑 收藏

 回复 引用 查看   
#1楼 2004-11-16 10:38 kwklover      
GOOD !


 回复 引用   
#2楼 2004-11-16 10:53 Ninputer[未注册用户]
在VB里这样都可以
Dim i As Int32
i = "23"

 回复 引用   
#3楼 2004-11-16 11:17 ???[未注册用户]
Int32 有TryParse 方法吗?
Double有。
难道是.Net2.0有?

 回复 引用 查看   
#4楼[楼主] 2004-11-16 12:28 Allen Lee      
Int32.TryParse方法是.NET 2.0或以上才提供的,文章最后一个Q已经说明了。
 回复 引用   
#5楼 2004-11-16 16:36 笔端
很好的东西,可是那究竟是怎么工作的?如果能更深入些一定是很有意思
 回复 引用 查看   
#6楼 2004-11-16 17:39 mysticApex      
正在使用,谢谢
我只能说:就数你最详细了。

我喜欢用VisualBasic的Val()函数,肯定不异常并解析正常:)

 回复 引用   
#8楼 2004-11-16 22:24 Koffer
受益匪浅阿!
谢谢!又是一个研究人员

 回复 引用   
#9楼 2004-11-17 09:54 Ninputer[未注册用户]
@ unruledboy

Val()是从字符串中取数,连daf324这样的字符串都可以。估计比较慢……

呵呵,整个系统中,估计要做这样的工作的代码行不多,纳秒级别的损耗无伤大雅;)
 回复 引用 查看   
#11楼 2004-11-29 08:52 dljsoft      
不错!
 回复 引用   
#12楼 2004-12-16 23:17 FreeD2d
可以
 回复 引用 查看   
#13楼 2005-08-09 22:56 chengbo      
好文,收藏了
 回复 引用   
#14楼 2005-08-23 19:31 lcj[未注册用户]
如何把string类转为double啊?请各位大虾指点指点啊[C#]
 回复 引用   
#15楼 2005-11-24 16:57 sicon[未注册用户]
good
 回复 引用 查看   
#16楼 2005-12-09 14:39 Stone      
up
 回复 引用 查看   
#17楼 2005-12-12 14:29 独孤求败      
研究的很透彻啊。。。。学习。
 回复 引用   
#18楼 2006-02-15 09:01 Benjamin[未注册用户]
文章不错。

不过,能解释一下三者关系就更好了
:P

 回复 引用 查看   
#19楼[楼主] 2006-03-02 11:12 Allen Lee      
To Benjamin:

Convert.ToInt32 会把最终的解析工作代理给 Int32.Parse,而 Int32.Parse 和 Int32.TryParse 则分别把解析工作直接代理给 Number.ParseInt32 和 Number.TryParseInt32,前者在出现解析错误时抛出异常,而后者则仅仅返回 false。

 回复 引用 查看   
#20楼 2006-05-10 12:41 zhfen      
学习中.....................................thanks
 回复 引用 查看   
#21楼 2006-07-04 15:46 OOP      
不错
 回复 引用   
#22楼 2006-07-08 09:51 arden[未注册用户]
thx
 回复 引用   
#23楼 2006-07-19 12:53 Champion Whole[未注册用户]
谢谢!
 回复 引用   
#24楼 2007-09-07 12:54 Timee[未注册用户]
切,这、两个我感觉哪个都能用。

站补
http://www.0o0web.com

 回复 引用 查看   
#25楼 2008-03-14 15:08 早班火车      
学习~
 回复 引用   
#26楼 2008-04-03 14:33 marktea[未注册用户]
学习中,受用受用
 回复 引用   
#27楼 2008-04-12 16:12 dddd[未注册用户]
dddd我支持

 回复 引用 查看   
#28楼 2008-06-05 01:13 光光GG      
so good.........
 回复 引用 查看   
#29楼 2009-01-14 14:29 ★海戰鷹      
楼主的帖子实在是写得太好了。文笔流畅,修辞得体,深得魏晋诸朝遗风,更将唐风宋骨发扬得入木三分,能在有生之年看见楼主的这个帖子 ,实在是我三生之幸啊
 回复 引用 查看   
#30楼[楼主] 2009-01-14 19:39 Allen Lee      
@★海戰鷹
你这份赞赏会不会太过夸张了呢。。。anyway,谢谢。。。

 回复 引用 查看   
#31楼 2009-01-17 00:19 oec2003      
good
 回复 引用 查看   
#32楼 2010-09-02 16:35 心翼      
不错 高手 学习了
 回复 引用 查看   
#33楼 2011-11-29 16:12 Rampage      
请假个问题,在执行这段话是int result = Int32.Parse(" $1,412 ", NumberStyles.Currency);出现错误,怎么解释?
 回复 引用 查看   
#34楼[楼主] 2011-11-29 17:18 Allen Lee      
@Rampage
我这边可以解释的了,正确输出1412。我这里的区域设置是英语(美国),我想你的错误可能和这个设置有关。你的错误具体是什么呢?

 回复 引用 查看   
#35楼 2011-12-01 11:49 Me_JinLee      
请教您一个问题,在提交软件的时候,market中不支持中文,但是我的软件界面有中文,怎么办,提交了一次 返回给我的错误信息是
Test Process Required:
1. Review the product description of the
application and verify that it is localized to the
target language.
2. Launch the application.
3. Verify that the UI text of the application is
localized to the target language.
难道界面不能用中文???

 回复 引用 查看   
#36楼[楼主] 2011-12-01 16:57 Allen Lee      
@Me_JinLee
有可能是提交的时候Default Language的选择和Assembly Information的Neutral Language不匹配?我搜了一下园子,找到两篇文章你可以参考一下:

http://www.cnblogs.com/aawolf/archive/2010/12/17/1909266.html

http://www.cnblogs.com/randylee/archive/2011/09/09/2172640.html

 回复 引用 查看   
#37楼 2011-12-01 18:46 Me_JinLee      
@Allen Lee
感谢博主的回复,太nice了!