1

说我有

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

我跑

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

当我输出a时,2 是 a 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 

似乎适用于基本示例。这有什么不安全的吗?

4

4 回答 4

3

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

于 2012-12-05T22:30:58.070 回答
2

编辑:这有效

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"}
于 2012-12-06T01:26:42.050 回答
1

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

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 

或作为单线

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"}
于 2012-12-05T22:58:37.490 回答
-1

我想不出您拥有的输入字符串的方法,但是如果您可以将其更改为

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

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

于 2012-12-05T22:34:50.270 回答