如何仅将数字的字符串哈希值转换为整数

我有从几个不同的XML数据库转储导入的哈希行,看起来像这样(但使用不同的键):

{"Id"=>"1", "Name"=>"Cat", "Description"=>"Feline", "Count"=>"123"} 

我尝试使用#to_i但它将非数字字符串转换为0

 "Feline".to_i # => 0 

但是我想要的是"Feline"保持字符串的方式,而上面例子中的IdCount变为整数1123

有没有一种简单的方法可以将数字的字符串值转换为整数?

使用内核#Integer :

 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_keysHash#with_values!Hash#with_keys! 做你期望他们做的事情,和Hash#modify ,希望二进制块返回一对值,修改哈希值。 有人建议将来将这些方法直接添加到Ruby核心。

一行答案:使用正则表达式方法

 h.merge(h) { |k, v| v.match(/\A[+-]?\d+?(\.\d+)?\Z/) ? v.to_i : v } 

使用整数方法

 h.merge(h) { |k, v| Integer(v) rescue v } 

我想你知道哪些字段应该是整数(你的消费代码可能取决于它),所以我建议你转换特定的字段。

 c = Hash[h.map { |k,v| [k, %w(Id Count).include?(k) ? Integer(v) : v ] }] 

我有一个类似的问题要解决,其中农药分析的结果作为异构(糟糕的设计!)格式进入系统…负整数作为特殊代码(未检测,未测试,未量化等…), nil作为未检测到的同义词,浮动用于量化化合物和字符串用于通过/失败布尔 …保持你的马,这是一个10年的生产运行,从来没有绿地编辑高度修补的应用程序;)

我从顶级rubists学到的两件事

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 

使用正则表达式和三元运算符,您可以将其合并到逻辑中:

 string =~ /^\d+$/ ? string.to_i : string 

这不仅会处理整数,还会处理所有数字。

 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 } 

感谢确定字符串是否为regexp 的有效浮点值

为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"