将Ruby哈希数组转换为JSON(漂亮)不使用stdlib?

时间:2015-01-02 16:53:14

标签: ruby json

根据这个问题,只是想知道如何在不使用Ruby stdlib'JSON'模块(以及JSON.pretty_generate方法)的情况下执行此操作。

所以我有一系列哈希看起来像:

[{"h1"=>"a", "h2"=>"b", "h3"=>"c"}, {"h1"=>"d", "h2"=>"e", "h3"=>"f"}]

我希望将其转换为如下所示:

[
  {
    "h1": "a",
    "h2": "b",
    "h3": "c",
  },
  {
    "h1": "d",
    "h2": "e",
    "h3": "f",
  }
]

我可以使用简单的gsub(array_of_hashes.to_s.gsub!(/ => /,“:”))将冒号火箭替换为冒号空间,但不确定如何生成它以使其看起来像上面的例子。我原本以为使用here-doc方法,但不确定这是最好的方法,而且我还没有设法让它工作。我是Ruby的新手,如果这很明显,请道歉! : - )

def to_json_pretty
        json_pretty = <<-EOM
[
  {
    "#{array_of_hashes.each { |hash| puts hash } }"
  },
]
EOM
        json_pretty
      end

3 个答案:

答案 0 :(得分:3)

通常,在不使用库的情况下使用JSON不仅仅需要几行代码。话虽这么说,JSON-ifying事物的最佳方式通常是递归地执行,例如:

def pretty_json(obj)
  case obj
  when Array
    contents = obj.map {|x| pretty_json(x).gsub(/^/, "  ") }.join(",\n")
    "[\n#{contents}\n]"
  when Hash
    contents = obj.map {|k, v| "#{pretty_json(k.to_s)}: #{pretty_json(v)}".gsub(/^/, "  ") }.join(",\n")
    "{\n#{contents}\n}"
  else
    obj.inspect
  end
end

答案 1 :(得分:0)

如果输入完全采用您呈现的格式而不是嵌套格式,这应该可以正常工作:

a =  [{"h1"=>"a", "h2"=>"b", "h3"=>"c"}, {"h1"=>"d", "h2"=>"e", "h3"=>"f"}]
hstart = 0
astart = 0
a.each do |b|
  puts "[" if astart == 0
  astart+=1
  b.each do |key, value|
    puts " {" if hstart == 0 
    hstart += 1
    puts "   " + key.to_s + ' : ' + value
    if hstart % 2 == 0 
      if hstart ==  a.collect(&:size).reduce(:+)
        puts " }"  
      else
        puts " },\n {"
      end
    end
  end
  puts "]" if astart == a.size
end

输出:

[
 {
   h1 : a
   h2 : b
 },
 {
   h3 : c
   h1 : d
 },
 {
   h2 : e
   h3 : f
 }
]

答案 2 :(得分:0)

你可以看看我的NeatJSON宝石,看看我是怎么做到的。具体来说,请查看neatjson.rb,它使用递归解决方案(通过proc)。

我的代码根据您提供的格式选项有很多变化,所以它显然不必像这样复杂。但是一般的模式是测试提供给你的方法/ proc的对象的类型,如果它很简单就将它序列化,或者(如果它是一个数组或哈希)重新调用每个方法/ proc的方法/ proc。里面的价值。

这是一个非常简化的版本(没有缩进,没有换行,硬编码间距):

def simple_json(object)
  js = ->(o) do
    case o
      when String               then o.inspect
      when Symbol               then o.to_s.inspect
      when Numeric              then o.to_s
      when TrueClass,FalseClass then o.to_s
      when NilClass             then "null"
      when Array                then "[ #{o.map{ |v| js[v] }.join ', '} ]"
      when Hash                 then "{ #{o.map{ |k,v| [js[k],js[v]].join ":"}.join ', '} }"
      else
        raise "I don't know how to deal with #{o.inspect}"
    end
  end
  js[object]
end


puts simple_json({a:1,b:[2,3,4],c:3})
#=> { "a":1, "b":[ 2, 3, 4 ], "c":3 }