我从几个不同的XML数据库转储导入的哈希行看起来像这样(但是使用不同的键):
{"Id"=>"1", "Name"=>"Cat", "Description"=>"Feline", "Count"=>"123"}
我尝试使用#to_i
,但它将非数字字符串转换为0
:
"Feline".to_i
# => 0
但我想要的是"Feline"
保持字符串的方式,而上例中的Id
和Count
变为整数1
和{{1 }}
是否有一种简单的方法可以将仅将数字的字符串值转换为整数?
答案 0 :(得分:9)
一行答案: 使用正则表达式方法
h.merge(h) { |k, v| v.match(/\A[+-]?\d+?(\.\d+)?\Z/) ? v.to_i : v }
使用整数方法
h.merge(h) { |k, v| Integer(v) rescue v }
答案 1 :(得分:7)
my_hash = {"Id"=>"1", "Name"=>"Cat", "Description"=>"Feline", "Count"=>"123"}
Hash[ my_hash.map{ |a, b| [ a,
begin
Integer b
rescue ArgumentError
b
end ] } ]
稍后添加:使用我的y_support
gem,您可以使哈希操作更简洁。
require 'y_support/core_ext/hash'
my_hash.with_values { |v| begin
Integer b
rescue ArgumentError
b
end }
YSupport
可由gem install y_support
安装,并提供符合您预期效果的Hash#with_keys
,Hash#with_values!
,Hash#with_keys!
以及Hash#modify
期望二进制块返回一对值,修改哈希值。有人建议将来将这些方法直接添加到Ruby核心。
答案 2 :(得分:1)
我想你知道哪些字段应该是整数(你的消费代码可能取决于它),所以我建议你转换特定的字段。
c = Hash[h.map { |k,v| [k, %w(Id Count).include?(k) ? Integer(v) : v ] }]
答案 3 :(得分:1)
我有一个相似问题需要解决,农药分析结果以异质(不良设计!)格式进入系统...负整数作为特殊代码(未检测到,未经测试) ,未量化等...),nil
作为未检测到的同义词,为量化的化合物浮动,并为通过/失败 boolean 的字符串浮动...等等,这是十年在生产环境中运行时间过长,从来没有未开发的高度修补的应用程序;)
两件事:
0) DON'T ITERATE-MODIFY AN ENUMERABLE (return a copy)
1) YOUR REGEX WON'T COVER ALL CASES
虽然我不是rescue
的忠实拥护者,但我认为这符合保持代码整洁的目的。因此,我一直在使用它来减轻我的输入:
ha = {
"p_permethrin" => nil,
"p_acequinocyl"=>"0.124",
"p_captan"=>"2.12",
"p_cypermethrin"=>"-6",
"p_cyfluthrin"=>"-6",
"p_fenhexamid"=>"-1",
"p_spinetoram"=>"-6",
"p_pentachloronitrobenzene"=>"-6",
"p_zpass"=>"true"
}
Hash[ha.map{|k,v| [k, (Float(v) rescue v)]}] # allows nil
Hash[ha.map{|k,v| [k, (Float(v) rescue v.to_s)]}] # nit to empty string
我什至
class Hash
# return a copy of the hash, where values are evaluated as Integer and Float
def evaluate_values
Hash[self.map{|k,v| [k, (Float(v) rescue v)]}]
end
end
答案 4 :(得分:0)
使用正则表达式和三元运算符,您可以将其合并到逻辑某处:
string =~ /^\d+$/ ? string.to_i : string
答案 5 :(得分:0)
这不仅会处理整数,还会处理所有数字。
my_hash = {"Id"=>"1", "Name"=>"Cat", "Description"=>"Feline", "Count"=>"123"}
result = my_hash.inject({}) { |result,(key,value)|
if value.match(/^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/)
result[key.to_sym] = value.to_i
else
result[key.to_sym] = value
end
result
}
感谢Determine if a string is a valid float value for regexp
答案 6 :(得分:-1)
为String定义一个新方法: String #to_number
class String
def to_number
Integer(self) rescue Float(self) rescue self
end
end
测试它:
"1".to_number => 1
"Cat".to_number => "Cat"