ChatGPT解决这个技术问题 Extra ChatGPT

在 Ruby 中解析 JSON 字符串

我有一个要在 Ruby 中解析的字符串:

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

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

Ruby 直接支持 JSON,并且至少从 Ruby v1.9.3 开始就已经支持,因此除非您使用的是旧版本,否则无需安装 gem。只需在您的代码中使用 require 'json'

A
Andrew Marshall

这看起来像 JavaScript Object Notation (JSON)。您可以解析驻留在某个变量中的 JSON,例如 json_string,如下所示:

require 'json'
JSON.parse(json_string)

如果您使用的是旧版 Ruby,则可能需要安装 json gem

Ruby 的其他 JSON 实现可能更适合某些用例:

YAJL C Ruby 绑定

JSON::流


您还可以将选项 symbolize_names 设置为 true,以便将键作为符号。示例:JSON.parse(string, symbolize_names: true) #=> {key: :value}
Ruby 直接支持 JSON,并且至少从 Ruby v1.9.3 开始就已经支持,因此除非您使用的是旧版本,否则无需安装 gem。只需在您的代码中使用 require 'json'
n
nevan king

只是为了扩展答案与如何处理解析的对象:

# 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

重要提示:'{ "a": "bob" }' 有效。 "{ 'a': 'bob' }" 不是。
@LinusAn 因为 JSON 需要在字符串周围加上双引号。请参阅 JSON 定义中的字符串 ( json.org ):“字符串是零个或多个 Unicode 字符的序列,用双引号括起来,使用反斜杠转义。”
在许多情况下,您希望将 JSON.parse 包装在 JSON::ParserError 的救援块中。
JSON.parse("[#{value}]")[0] 以避免错误 A JSON text must at least contain two octets!
您能否通过包含来自 shop.json 的示例数据来完成您的答案?
t
the Tin Man

从 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


t
the Tin Man

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

JSON.parse(string)

t
the Tin Man

这有点晚了,但我遇到了一些有趣的东西,似乎很重要。

我不小心写了这段代码,它似乎工作:

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。 Ruby v1.9.3 中引入了 JSON 解析。
这样做的原因是语义上(大多数)JSON 是有效的 YAML(尤其是 YAML 1.2)
A
Adverbly

在这里看不到任何提到直接解析为哈希以外的对象的答案,但可以使用文档记录不佳的 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 选项。


m
mycargus

我建议使用 Oj,因为它比标准 JSON 库快得多。

https://github.com/ohler55/oj

(see performance comparisons here)


E
Erik Madsen

如果您想反序列化为您自己的类而不是 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>>