Ruby中的安全整数解析
时间:2020-03-05 18:49:12 来源:igfitidea点击:
我有一个字符串,例如" 123",我想将其转换为" 123"。
我知道我们可以简单地执行" some_string.to_i",但这会将" lolipops"转换为" 0",这并不是我想到的效果。当我尝试将无效的东西转换为带有令人痛苦的"异常"的东西时,我希望它能炸开我的脸。否则,我无法区分有效的" 0"和根本不是数字的东西。
编辑:我一直在寻找标准的方式来做到这一点,而无需使用正则表达式。
解决方案
回答
Ruby内置了以下功能:
Integer('1001') # => 1001 Integer('1001 nights') # ArgumentError: invalid value for Integer: "1001 nights"
正如Joseph Pecoraro在回答中所指出的那样,我们可能要注意查找有效的非十进制数字的字符串,例如以" 0x"开头的十六进制和以" 0b"开头的二进制,以及可能更复杂的以零开头的数字被解析为八进制。
Ruby 1.9.2为基数添加了可选的第二个参数,因此可以避免上述问题:
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+$/)
回答
someString = "asdfasd123" number = someString.to_i if someString != number.to_s puts "oops, this isn't a number" end
可能不是最干净的方法,但应该可以。
回答
还请注意当前接受的解决方案可能会对解析十六进制,八进制和二进制数产生影响:
>> Integer('0x15') # => 21 >> Integer('0b10') # => 2 >> Integer('077') # => 63
在以" 0x"或者" 0X"开头的Ruby数字中,十六进制为" 0b"或者" 0B",而仅以八进制表示" 0"。如果这不是所需的行为,则可能需要将该行为与其他一些首先检查字符串是否与模式匹配的解决方案结合起来。像/ \ d + /
正则表达式,等等。
回答
回复:克里斯的答案
实现让" 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
回答
我在上一个项目中不得不处理这个问题,我的实现是相似的,但有一点不同:
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.8、1.9来说可以):
>> Integer(:foobar) => 26017 >> Integer(:yikes) => 26025
因此,如果我们不确定要传递的内容,请确保添加.to_s
。