【问题标题】:Parsing a JSON string in Ruby在 Ruby 中解析 JSON 字符串
【发布时间】: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'

标签: ruby 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 实现可能更适合某些用例:

    【讨论】:

    • 您还可以将选项 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>>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-21
            • 1970-01-01
            • 2018-09-18
            相关资源
            最近更新 更多