在Ruby中解析JSON字符串

426

我有一个字符串,想在Ruby中解析它:

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'

有没有简单的方法提取数据?


27
JSON 在 Ruby 中得到了直接支持,至少从 Ruby v1.9.3 开始就有了支持,因此除非您正在使用较旧的版本,否则无需安装 gem。只需在您的代码中使用 require 'json' 即可。 - the Tin Man
8个回答

641

43
您可以将选项symbolize_names设置为true,以便获得键作为符号。例如:JSON.parse(string, symbolize_names: true) #=> {key: :value} - Nando Sousa
33
JSON可以直接在Ruby中使用,且至少从Ruby v1.9.3版本开始支持,所以除非你使用的是较旧的版本,否则无需安装gem。在你的代码中,只需使用require 'json'即可。 - the Tin Man

239

仅仅扩展一下对已解析对象的处理方法:

# JSON Parsing example
require "rubygems" # don't need this if you're Ruby v1.9.3 or higher
require "json"

string = '{"desc":{"someKey":"someValue","anotherKey":"value"},"main_item":{"stats":{"a":8,"b":12,"c":10}}}'
parsed = JSON.parse(string) # returns a hash

p parsed["desc"]["someKey"]
p parsed["main_item"]["stats"]["a"]

# Read JSON from a file, iterate over objects
file = open("shops.json")
json = file.read

parsed = JSON.parse(json)

parsed["shop"].each do |shop|
  p shop["id"]
end

9
重要提示:'{ "a": "bob" }' 是有效的。"{ 'a': 'bob' }" 不是有效的。 - Ziggy
7
@LinusAn 因为 JSON 要求字符串需要用双引号括起来。 请参考 JSON 定义中关于字符串的描述(http://www.json.org/):"字符串是零个或多个 Unicode 字符序列,被双引号包裹,使用反斜杠进行转义。" - endorama
1
在许多情况下,您希望将JSON.parse包装在JSON::ParserError的救援块中。 - johnml
JSON.parse("[#{value}]")[0] 转换用于避免 A JSON text must at least contain two octets! 错误。 - Rivenfall
你能否在回答中包含一个从shops.json中提取的样例数据的完整示例呢? - barlop

42

从 Ruby v1.9.3 开始,您无需安装任何 Gem 就可以解析 JSON,只需使用 require 'json'

require 'json'

json = JSON.parse '{"foo":"bar", "ping":"pong"}'
puts json['foo'] # prints "bar"

请在 Ruby-Doc 中查看 JSON


18

看起来是一个JSON字符串。你可以使用许多JSON库,它就像这样简单:

JSON.parse(string)

9

这里没有提到将解析直接转换成除哈希外的其他对象的答案,但是可以使用文档不太完整的 object_class 选项来实现(详见https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/JSON.html):

JSON.parse('{"foo":{"bar": 2}}', object_class: OpenStruct).foo.bar
=> 2

更好的理解该选项的方式是“一个JSON对象转换为Ruby类”,这解释了为什么默认为Hash。同样,对于JSON数组也有array_class选项。

7
这有点晚了,但我遇到了一些有趣的东西,似乎很重要需要贡献出来。
我意外地写了这段代码,而且它似乎可以工作:
require 'yaml'
CONFIG_FILE = ENV['CONFIG_FILE'] # path to a JSON config file 
configs = YAML.load_file("#{CONFIG_FILE}")
puts configs['desc']['someKey']

我很惊讶地发现它可以工作,因为我正在使用YAML库,但它确实可以。

重要的原因在于yaml与Ruby一起内置,所以不需要gem安装。

我使用的是1.8.x和1.9.x版本,因此json库没有内置,但在2.x版本中已经内置。

因此,在低于2.0版本的情况下,这是提取数据的最简单方法。


是的,JSON实际上是由Psych代码解析的,在Ruby中也解析YAML。而JSON解析是在Ruby v1.9.3中引入的。 - the Tin Man
2
这个方法有效的原因是,从语义上讲,大多数 JSON 是有效的 YAML(特别是 YAML 1.2)。 - Justin Ohms
我在 Ruby 2.3.8 上遇到了 "undefined method `load_file' for JSON:Module" 的错误。 - Nakilon

4

1

如果你想将反序列化应用到自己的类,而不是OpenStruct,那么只需要进行一些简单的工作即可实现以下操作:

require 'json'
# result is an instance of MyClass
result = JSON.parse(some_json_string, object_class: MyClass)

您所需要做的就是提供一个无参构造函数并实现 #[]= 方法,这个方法将会被 JSON.parse 调用。如果您不想公开它,只需将其设为私有即可:

class MyClass
  attr_reader :a, :b

  private

  def []=(key, value)
    case key
    when 'a' then @a = value
    when 'b' then @b = value
    end
  end
end

在irb中尝试:

> JSON.parse('{"a":1, "b":2}', object_class: MyClass)
=> #<MyClass:0x00007fe00913ae98 @a=1, @b=2>

这种方法的一个注意点是它仅适用于扁平结构,因为object_class参数实际上告诉解析器在字符串中反序列化JSON对象时应该使用哪个类,而不是Hash(请参阅类似操作array_class参数以处理JSON数组)。对于嵌套结构,这意味着您将使用相同的类来表示所有层级。
> JSON.parse('{"a":1, "b":{ "a": 32 }}', object_class: MyClass)
=> #<MyClass:0x00007fb5110b2b38 @a=1, @b=#<MyClass:0x00007fb5110b2908 @a=32>>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接