在 Ruby 中解析 JSON 字符串

Posted

技术标签:

【中文标题】在 Ruby 中解析 JSON 字符串【英文标题】:Parsing a JSON string in Ruby 【发布时间】:2011-07-21 14:34:46 【问题描述】:

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

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

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

【问题讨论】:

Ruby 直接支持 JSON,至少从 Ruby v1.9.3 开始就支持 JSON,因此除非您使用的是旧版本,否则无需安装 gem。只需在您的代码中使用require 'json' 【参考方案1】:

它看起来像一个 JSON 字符串。您可以使用许多 JSON 库之一,而且很简单:

JSON.parse(string)

【讨论】:

【参考方案2】:

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

require 'json'
JSON.parse(json_string)

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


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

YAJL C Bindings for Ruby JSON::Stream

【讨论】:

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

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

# 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!【参考方案4】:

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

https://github.com/ohler55/oj

(see performance comparisons here)

【讨论】:

【参考方案5】:

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

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

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)【参考方案6】:

从 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。

【讨论】:

【参考方案7】:

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

【讨论】:

【参考方案8】:

如果您想反序列化为您自己的类而不是 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(参见类似的参数 @ 987654328@ 用于 JSON 数组的类似操作)。对于嵌套结构,这意味着您将使用同一个类来表示所有层:

> JSON.parse('"a":1, "b": "a": 32 ', object_class: MyClass)
=> #<MyClass:0x00007fb5110b2b38 @a=1, @b=#<MyClass:0x00007fb5110b2908 @a=32>>

【讨论】:

以上是关于在 Ruby 中解析 JSON 字符串的主要内容,如果未能解决你的问题,请参考以下文章

何时在 Ruby 的 JSON 库中使用转储与生成与 to_json 以及加载与解析?

如何转义json字符串中的单引号? JSON::ParserError Ruby

从 JSON 字符串中删除所有缩进和空格,除了它在 Ruby 中的值之外

为啥我不能解析保存到 Ruby 中变量的日期字符串?

Ruby - 如何在解析的json中访问键值

解析 .erb 文件并返回字符串/Ruby 标记中的所有内容