Ruby:在查询字符串中获取值的正确类型

说我有

str = "a=2&b=3.05&c=testing" 

我跑

 require 'cgi' out = {} CGI::parse(str).each { |k,v| out[k] = v[0] } 

当我输出a ,2是一个string ,当我希望它是一个Int

 out['a'] // "2" (instead of int 2) out['b'] // "3.05" (instead of float 3.05) 

有没有办法从查询字符串中更正类型?

更新:

添加此方法以测试数字

 def is_a_number?(s) s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true end 

并在解析期间

 CGI::parse(url).each do |k,v| val = v[0] if is_a_number? val val = val.include?('.') ? val.to_f : val.to_i end out[k] = val end 

似乎可以使用基本示例。 这有什么不安全的吗?

编辑:这是有效的

 require 'cgi' str = "a=2&b=3.05&c=testing" out = {} def typecasted(str) [str.to_i, str.to_f, str].find { |cast| cast.to_s == str } end CGI::parse(str).each do |key, val| out[key] = typecasted val.first end p out # => {"a"=>2, "b"=>3.05, "c"=>"testing"} 

简短的回答是否定的,没有办法只是得到正确的类型。 您可以编写自己的解析器,尝试根据正则表达式匹配进行猜测。 处理它的典型方法是根据每个参数的预期类型手动解析它们。 您可以调用to_ito_f之类的方法将它们转换为您想要的类型。

如果你像这样解析它,你应该没有问题

 out = {} CGI::parse(str).each do |k, v| v, v = (v = v.first), (v if v[/[a-zA-Z]/]) || [v.to_i, v.to_f].max out.merge!(Hash[k, v]) end 

结合AJcodez的技术,这给出了

 out = {} CGI::parse(str).each do |k, v| v, out[k] = (v = v.first), [v.to_i, v.to_f, v].find { |c| c.to_s == v } end 

或者作为一个class轮

 Hash[*CGI::parse(str).map {|k, v| v = v.first; [k, [v.to_i, v.to_f, v].find { |c| c.to_s == v }]}.flatten] 

 {"a"=>2, "b"=>3.05, "c"=>"testing"} 

我想不出你有这个输入字符串的方法,但是你可以改变它

 str = "a=2&b=3.05&c='testing'" 

(注意单引号),你可以在每个值上使用eval函数,让ruby猜测类型。