这基于“How to convert a String to Integer or Float”。
如果我想使用Ruby的内置转换机制将数字字符串输入转换为“最合适的类型”,我可以这样做:
@ubuntu:~/Downloads$ sudo service dse start
Java executable not found (hint: set JAVA_HOME)
@ubuntu:~/Downloads$ echo $JAVA_HOME
/opt/jdk1.8.0_111
@ubuntu:~/Downloads$ java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
但这种暴力方法调用看起来很脏。有更优雅的方式来解决这个问题吗?我可以检查值是def convert(input)
value = Integer(input) rescue nil
value ||= Float(input) rescue nil
value ||= Rational(input) rescue nil
value
end
convert('1') #=> 1
convert('1_000') #=> 1000
convert('0xff') #=> 255
convert('0.5') #=> 0.5
convert('1e2') #=> 100.0
convert('1/2') #=> (1/2)
convert('foo') #=> nil
,Integer()
还是Float()
的有效输入,以便我可以更加可控地调用这些方法?
答案 0 :(得分:2)
使用尾随救援让我感到畏缩,因为它可以掩盖底层代码的问题,因为它会捕获Exception而不是ArgumentError,这是失败的尝试转换会引发的。这不简洁,但它处理了相应的例外:
def convert(input)
value = begin
Integer(input)
rescue ArgumentError
nil
end
value ||= begin
Float(input)
rescue ArgumentError
nil
end
value ||= begin
Rational(input)
rescue ArgumentError
nil
end
value
end
convert('1') # => 1
convert('1_000') # => 1000
convert('0xff') # => 255
convert('0.5') # => 0.5
convert('1e2') # => 100.0
convert('1/2') # => (1/2)
convert('foo') # => nil
在考虑了一下后,似乎可以将其干掉:
def convert(input)
[:Integer, :Float, :Rational].each do |m|
begin
return Kernel.method(m).call(input)
rescue ArgumentError
end
end
nil
end
convert('1') # => 1
convert('1_000') # => 1000
convert('0xff') # => 255
convert('0.5') # => 0.5
convert('1e2') # => 100.0
convert('1/2') # => (1/2)
convert('foo') # => nil
正如Jörn所指出的,上述情况并非如此。我使用内核来获取Integer()
,Float()
和Rational
,因为这是他们定义的地方,但实际上Object是从内核继承的地方。
当我知道有一种间接调用方法的好方法时,有一天,但call
在我的脑海中,而不是send
正如斯蒂芬指出的那样。所以,这是一个更简洁的方法,从:
return Object.send(m, input)
但是,这可以简化为:
return send(m, input)
导致:
def convert(input)
[:Integer, :Float, :Rational].each do |m|
begin
return send(m, input)
rescue ArgumentError
end
end
nil
end
convert('1') # => 1
convert('1_000') # => 1000
convert('0xff') # => 255
convert('0.5') # => 0.5
convert('1e2') # => 100.0
convert('1/2') # => (1/2)
convert('foo') # => nil
答案 1 :(得分:1)
由于某些原因,您希望将"0.3"
转换为3e-1
而不是3/10
,这可能会以更明确的方式完成。毕竟,在引擎盖下,ruby解析器中存在相同的识别机制:
def convert input
raise unless String === input && input[/\A_|_\z|__/].nil?
input = input.strip.delete('_')
case input
when /\A-?\d+\z/ then Integer(input)
when /\A-?0x[\da-f]+\z/i then Integer(input)
when /\A-?(\d*\.)?\d+(e-?\d+)?\z/i then Float(input)
when /\A-?(\d*\.)?\d+(e-?\d+)?\/\d+\z/i then Rational(input)
end
end
这可以按预期工作:)
答案 2 :(得分:1)
在the Tin Man's answer上捎带,可以使用模块覆盖Kernel
的默认行为:
module SafeConvert
def Integer(*) ; super ; rescue ArgumentError ; end
def Float(*) ; super ; rescue ArgumentError ; end
def Rational(*) ; super ; rescue ArgumentError ; end
end
这会将代码缩短为:
class Helper
include SafeConvert
def convert(input)
Integer(input) || Float(input) || Rational(input)
end
end