我有一个字符串,比如说'123'
,我想将它转换为整数123
。
我知道你可以简单地做some_string.to_i
,但这会转换'lolipops'
为0
,这不是我想要的效果。当我尝试转换无效的东西时,我希望它在我的脸上炸开,带有美好而痛苦的Exception
. 否则,我无法区分有效0
和根本不是数字的东西。
编辑:我正在寻找没有正则表达式技巧的标准方法。
我有一个字符串,比如说'123'
,我想将它转换为整数123
。
我知道你可以简单地做some_string.to_i
,但这会转换'lolipops'
为0
,这不是我想要的效果。当我尝试转换无效的东西时,我希望它在我的脸上炸开,带有美好而痛苦的Exception
. 否则,我无法区分有效0
和根本不是数字的东西。
编辑:我正在寻找没有正则表达式技巧的标准方法。
Ruby 内置了这个功能:
Integer('1001') # => 1001
Integer('1001 nights')
# ArgumentError: invalid value for Integer: "1001 nights"
正如Joseph Pecoraro在回答中指出的那样,您可能需要注意有效的非十进制数字的字符串,例如以0x
十六进制和0b
二进制开头的字符串,以及可能更棘手的以零开头的数字,这些数字将被解析为八进制。
Ruby 1.9.2 为 radix 添加了可选的第二个参数,因此可以避免上述问题:
Integer('23') # => 23
Integer('0x23') # => 35
Integer('023') # => 19
Integer('0x23', 10)
# => #<ArgumentError: invalid value for Integer: "0x23">
Integer('023', 10) # => 23
这可能有效:
i.to_i if i.match(/^\d+$/)
还要注意当前接受的解决方案可能对解析十六进制、八进制和二进制数产生的影响:
>> Integer('0x15')
# => 21
>> Integer('0b10')
# => 2
>> Integer('077')
# => 63
0x
在 Ruby 中,以or开头的数字0X
是十六进制的,0b
或者0B
是二进制的,只是0
八进制的。如果这不是您想要的行为,您可能希望将其与其他一些检查字符串是否首先匹配模式的解决方案结合起来。比如/\d+/
正则表达式等。
接受的解决方案的另一个意外行为(1.8、1.9 可以):
>> Integer(:foobar)
=> 26017
>> Integer(:yikes)
=> 26025
因此,如果您不确定传入的是什么,请确保添加.to_s
.
我喜欢 Myron 的回答,但它患有“我不再使用 Java/C# 所以我再也不会使用继承”的 Ruby 病。打开任何类都可能充满危险,应谨慎使用,尤其是当它是 Ruby 核心库的一部分时。我并不是说永远不要使用它,但它通常很容易避免并且有更好的选择,例如
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
然后,当您希望使用一个可能是数字的字符串时,很清楚您在做什么,并且您不会破坏任何核心类,例如
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 是为人服务的,而为人服务意味着清晰。通过变量名和类名命名一个对象会使事情变得更清晰。
我在上一个项目中不得不处理这个问题,我的实现是相似的,但有点不同:
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
someString = "asdfasd123"
number = someString.to_i
if someString != number.to_s
puts "oops, this isn't a number"
end
可能不是最干净的方法,但应该可以。
回复:克里斯的回答
您的实现让我们通过“1a”或“b2”之类的东西。这个怎么样:
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
这输出:
100
1a is invalid
b2 is invalid
t is invalid