我有一个字符串,例如'123',我想将其转换为整数123。
我知道您可以简单地执行some_string.to_i,但这会将'lolipops'转换为0,这不是我想到的效果。 当我尝试使用无效且令人痛苦的Exception转换无效内容时,我希望它能炸开我的脸。 否则,我无法区分有效的0和根本不是数字的东西。
编辑:我正在寻找这样做的标准方法,而无需使用正则表达式。
Ruby内置了以下功能:
1 2 3
| Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer:"1001 nights" |
正如Joseph Pecoraro在回答中所指出的那样,您可能要注意观察有效的非十进制数字的字符串,例如以0x表示十六进制和0b表示二进制的字符串,以及可能更复杂的以零开头的数字,这些字符串将被解析为八进制。
Ruby 1.9.2为基数添加了可选的第二个参数,因此可以避免上述问题:
1 2 3 4 5 6
| Integer('23') # => 23
Integer('0x23') # => 35
Integer('023') # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer:"0x23">
Integer('023', 10) # => 23 |
这可能起作用:
1
| i.to_i if i.match(/^\d+$/) |
还请注意当前接受的解决方案可能会对解析十六进制,八进制和二进制数产生影响:
1 2 3 4 5 6
| >> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63 |
在以0x或0x开头的Ruby数字中,十六进制是0b或0b是二进制,而0是八进制。如果这不是所需的行为,则可能需要将该行为与其他一些首先检查字符串是否与模式匹配的解决方案结合起来。像/\d+/正则表达式等。
可接受的解决方案的另一个意外行为(使用1.8、1.9即可):
1 2 3 4
| >> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025 |
因此,如果不确定传入的内容,请确保添加.to_s。
我喜欢Myron的答案,但是它遭受了"我不再使用Java / C#,所以我再也不会使用继承"的Ruby疾病了。打开任何类都可能充满危险,应谨慎使用,尤其是当它是Ruby核心库的一部分时。我并不是说永远不要使用它,但是通常很容易避免,并且有更好的选择,例如
1 2 3 4 5 6 7
| class IntegerInString < String
def initialize( s )
fail ArgumentError,"The string '#{s}' is not an integer in a string, it's just a string." unless s =~ /^\-?[0-9]+$/
super
end
end |
然后,当您希望使用可能是数字的字符串时,很清楚您在做什么,并且不会破坏任何核心类,例如
1 2 3 4 5 6
| n = IntegerInString.new"2"
n.to_i
# => 2
IntegerInString.new"blob"
ArgumentError: The string 'blob' is not an integer in a string, it's just a string. |
您可以在初始化中添加各种其他检查,例如检查二进制数等。但是,最主要的是Ruby是为人服务的,而为人服务则意味着清晰。通过对象的变量名和类名来命名它使事情变得更加清晰。
我必须在上一个项目中处理此问题,并且实现方式相似,但又有所不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class NotAnIntError < StandardError
end
class String
def is_int?
self =~ /^-?[0-9]+$/
end
def safe_to_i
return self.to_i if is_int?
raise NotAnIntError,"The string '#{self}' is not a valid integer.", caller
end
end
class Integer
def safe_to_i
return self
end
end
class StringExtensions < Test::Unit::TestCase
def test_is_int
assert"98234".is_int?
assert"-2342".is_int?
assert"02342".is_int?
assert !"+342".is_int?
assert !"3-42".is_int?
assert !"342.234".is_int?
assert !"a342".is_int?
assert !"342a".is_int?
end
def test_safe_to_i
assert 234234 == 234234.safe_to_i
assert 237 =="237".safe_to_i
begin
"a word".safe_to_i
fail 'safe_to_i did not raise the expected error.'
rescue NotAnIntError
# this is what we expect..
end
end
end |
1 2 3 4 5
| someString ="asdfasd123"
number = someString.to_i
if someString != number.to_s
puts"oops, this isn't a number"
end |
可能不是最干净的方法,但是应该可以。
回复:克里斯的答案
您的实现让" 1a"或" b2"之类的东西通过。怎么样呢:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def safeParse2(strToParse)
if strToParse =~ /\A\d+\Z/
strToParse.to_i
else
raise Exception
end
end
["100","1a","b2","t"].each do |number|
begin
puts safeParse2(number)
rescue Exception
puts"#{number} is invalid"
end
end |
输出:
1 2 3 4
| 100
1a is invalid
b2 is invalid
t is invalid |