Ruby JSON 解析修改了 Hash 键

假设我得到了这个 Hash:

{
:info => [
{
:from => "Ryan Bates",
:message => "sup bra",
:time => "04:35 AM"
}
]
}

我可以通过 hash[:info]调用信息数组。

现在,当我把它转换成 JSON (JSON.generate) ,然后解析它(JSON.parse)时,我得到了这个散列:

{
"info" => [
{
"from" => "Ryan Bates",
"message" => "sup bra",
"time" => "04:35 AM"
}
]
}

现在如果我使用 hash[:info],它返回 nil,但是如果我使用 hash["info"],它就不返回。

为什么会这样? 有没有办法修复这种不兼容性(除了从一开始就使用字符串键之外) ?

56665 次浏览

简而言之,没有。这样想吧,在 JSON 中存储符号和在 JSON 存储字符串是一样的。因此,在解析 JSON 字符串时,您不可能区分两者。当然,您可以将字符串键转换回符号,甚至可以构建一个类来与 JSON 交互,JSON 可以自动完成这项工作,但是我建议只使用字符串。

但是,仅仅是为了这个问题,下面是这个问题以前被问到的答案:

将 json 格式的键值对转换为以符号作为键的 ruby 散列的最佳方法是什么?

JSON 解码散列丢失符号

或者是 无差别访问

JSON 生成器将符号转换为字符串,因为 JSON 不支持符号。由于 JSON 键都是字符串,因此解析 JSON 文档将在默认情况下生成一个包含字符串键的 Ruby 散列。

可以通过使用 symbolize_names选项告诉解析器使用符号而不是字符串。

例如:

original_hash = {:info => [{:from => "Ryan Bates", :message => "sup bra", :time => "04:35 AM"}]}
serialized = JSON.generate(original_hash)
new_hash = JSON.parse(serialized, {:symbolize_names => true})


new_hash[:info]
#=> [{:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}]

参考资料: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse

  1. 使用 ActiveSupport: : JSON.decode,它将使您更容易地交换 json 解析器
  2. 使用 ActiveSupport: : JSON.decode (my _ json,symize _ Names: true)

这将递归地表示散列中的所有键。

(在 Ruby 2.0上确认)

我解决了类似的问题,在它上面调用了 with _ different _ access 方法

这里我有一个 json 字符串,我们可以把它赋给变量 s

s = "{\"foo\":{\"bar\":\"cool\"}}"

现在我可以使用 JSON 类解析数据并将其赋给 h

h = JSON.parse(s).with_indifferent_access

这将生成一个散列,该散列可以接受字符串或符号作为键

h[:foo]["bar"]
#=> "cool"

你不能这样使用那个选项

ActiveSupport::JSON.decode(str_json, symbolize_names: true)

在 Rails 4.1或更高版本中,ActiveSupport::JSON.decode不再接受 一个 MultiJSON 的选项散列 已经被移除了。

您可以使用 组合键来处理它。 警告: 它仅适用于解析为哈希的 JSON 字符串。

ActiveSupport::JSON.decode(str_json).symbolize_keys

可以修改散列中的所有键,将它们从字符串转换为符号:

symbol_hash = Hash[obj.map{ |k,v| [k.to_sym, v] }]


puts symbol_hash[:info]
# => {"from"=>"Ryan Bates", "message"=>"sup bra", "time"=>"04:35 AM"}

不幸的是,对嵌套在数组中的散列不起作用。但是,您可以编写一个小小的递归方法来转换所有哈希键:

def symbolize_keys(obj)
#puts obj.class # Useful for debugging
return obj.collect { |a| symbolize_keys(a) } if obj.is_a?(Array)
return obj unless obj.is_a?(Hash)
return Hash[obj.map{ |k,v| [k.to_sym, symbolize_keys(v)] }]
end


symbol_hash = symbolize_keys(hash)
puts symbol_hash[:info]
# => {:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}