关于字符串:Ruby中的安全整数解析

关于字符串:Ruby中的安全整数解析

Safe integer parsing in Ruby

我有一个字符串,例如'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

在以0x0x开头的Ruby数字中,十六进制是0b0b是二进制,而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

推荐阅读

    linux命令执行很慢?

    linux命令执行很慢?,软件,系统,工具,分析,机构,服务,培训,教育,数字,数据,Lin

    linux命令行执行py?

    linux命令行执行py?,系统,环境,官网,一致,文件,程序,脚本,源文件,后台,终端,l

    linux查看执行命令?

    linux查看执行命令?,系统,服务,情况,信息,命令,暂停,标准,概念,实时,第一,lin

    linux命令连续执行?

    linux命令连续执行?,连续,通信,工具,数据,代码,命令,设备,系统,发行,情况,如

    linux执行命令卡住?

    linux执行命令卡住?,系统,环境,密码,数据,信息,分析,软件,异常,服务,命令,Lin

    linux拼接字符串命令?

    linux拼接字符串命令?,系统,工作,代码,工具,名称,信息,地址,时间,数据,命令,l

    linux地址转换命令是?

    linux地址转换命令是?,地址,系统,代码,密码,网络,信息,服务,电脑,设备,报告,

    linux命令执行不动了?

    linux命令执行不动了?,系统,电脑,数据,管理,信息,密码,命令,环境,地方,分析,l

    linux无效对象的命令?

    linux无效对象的命令?,软件,系统,单位,网络,管理,术语,检测,电脑,环境,风险,l

    linux脚步中执行命令?

    linux脚步中执行命令?,工具,代码,命令,名称,系统,连续,环境,发行,文件,终端,l

    linux后台执行命令?

    linux后台执行命令?,暂停,状态,系统,服务,标准,命令,后台,地方,进程,终端,lin

    linux执行权限命令行?

    linux执行权限命令行?,地址,电脑,系统,数字,工作,权限,目录,文件,新增,信息,L

    linux命令的执行时间?

    linux命令的执行时间?,时间,系统,周期,信息,命令,设备,环境,地址,基础,进程,l

    添加字符串命令linux?

    添加字符串命令linux?,情况,名称,文件,位置,名字,地方,连续,信息,命令,内容,L

    linuxip命令无效?

    linuxip命令无效?,地址,信息,网络,系统,电脑,传播,状态,软件,不了,命令,linux

    程序执行linux命令?

    程序执行linux命令?,系统,工作,地址,环境,信息,管理,命令,文件,目录,程序,lin

    linux执行2个命令?

    linux执行2个命令?,工作,系统,基础,命令,基础知识,信息,管理,在线,概念,第一

    linux命令批量执行?

    linux命令批量执行?,系统,代码,工作,周期性,数据,定期,环境,命令,文件,脚本,l

    linux二进制执行命令?

    linux二进制执行命令?,系统,工作,情况,代码,信息,位置,地址,命令,文件,目录,L

    linux执行退出命令?

    linux执行退出命令?,档案,状态,工作,命令,信息,地址,电脑,系统,编辑,文件,lin