Ruby JSON 解析更改哈希键
Posted
技术标签:
【中文标题】Ruby JSON 解析更改哈希键【英文标题】:Ruby JSON parse changes Hash keys 【发布时间】:2011-11-24 12:28:01 【问题描述】:假设我有这个哈希:
:info => [
:from => "Ryan Bates",
:message => "sup bra",
:time => "04:35 AM"
]
我可以通过 hash[:info]
调用 info 数组。
现在当我把它转换成 JSON (JSON.generate),然后解析它 (JSON.parse),我得到了这个哈希:
"info" => [
"from" => "Ryan Bates",
"message" => "sup bra",
"time" => "04:35 AM"
]
现在,如果我使用hash[:info]
,它会返回nil
,但如果我使用hash["info"]
,则不会。
这是为什么?有没有办法解决这个不兼容问题(除了从一开始就使用字符串键)?
【问题讨论】:
【参考方案1】: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
【讨论】:
我认为现在是 :symbolize_keys (rubydoc.info/gems/multi_json/1.3.2/MultiJson) @Boushley:不,仍然是symbolize_names
。我的回答引用了 Ruby 标准库附带的 JSON 引擎。您正在引用第三方 gem。【参考方案2】:
简而言之,不。这样想,在 JSON 中存储符号与在 JSON 中存储字符串是一样的。因此,在解析 JSON 字符串时,您可能无法区分两者。您当然可以将字符串键转换回符号,或者实际上甚至构建一个与 JSON 交互的类,它会自动执行此操作,但我建议只使用字符串。
但是,为了这个目的,这里是之前被问到这个问题的答案:
what is the best way to convert a json formatted key value pair to ruby hash with symbol as key?
ActiveSupport::JSON decode hash losing symbols
或者也许是HashWithIndifferentAccess
【讨论】:
感谢您的链接,但就像您说的,我将使用字符串作为键【参考方案3】:我通过调用 with_indifferent_access 方法解决了我的类似问题
这里我有一个 json 字符串,我们可以将它分配给变量 s
s = "\"foo\":\"bar\":\"cool\""
所以现在我可以用 JSON 类解析数据并将其分配给 h
h = JSON.parse(s).with_indifferent_access
这将产生一个可以接受字符串或符号作为键的哈希
h[:foo]["bar"]
#=> "cool"
【讨论】:
with_indifferent_access
是否通过 Rails 生态系统中的某些东西添加到 Hash
中?
@Mark 你是对的。这是一个链接api.rubyonrails.org/v4.2.5/classes/ActiveSupport/…【参考方案4】:
-
使用 ActiveSupport::JSON.decode,它可以让您更轻松地交换 json 解析器
使用 ActiveSupport::JSON.decode(my_json, symbolize_names: true)
这将递归地表示散列中的所有键。
(在 ruby 2.0 上确认)
【讨论】:
似乎在 rails 4.1 中被移除了? edgeguides.rubyonrails.org/… 和 api.rubyonrails.org/classes/ActiveSupport/JSON.html 状态选项支持已删除【参考方案5】:可以修改散列中的所有键,将它们从字符串转换为符号:
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"
【讨论】:
【参考方案6】:你不能像这样使用那个选项
ActiveSupport::JSON.decode(str_json, symbolize_names: true)
在 Rails 4.1 或更高版本中,
ActiveSupport::JSON.decode
不再接受 MultiJSON 的选项哈希。 MultiJSON 到了生命的尽头,并且 已被删除。
您可以使用symbolize_keys 来处理它。 警告:它仅适用于解析为哈希的 JSON 字符串。
ActiveSupport::JSON.decode(str_json).symbolize_keys
【讨论】:
以上是关于Ruby JSON 解析更改哈希键的主要内容,如果未能解决你的问题,请参考以下文章
在更改 ruby 中的某些值后,如何维护具有原始值的哈希副本?