为Array of Arrays写一个JSON文件

时间:2014-07-07 15:31:00

标签: ruby arrays json

我有几个用JSON编写的nx3数组,因此可以在Ruby中进一步读取它们。

我完成了代码,但是JSON.parse在第二个数组写入文件时返回错误。如何编写JSON,以便可以单独读取每个数组?

这是代码和编写的JSON文件。

require 'json'
wp = []
wp[0]=[704/4,1124/4,0]
wp[1]=[704/4,1608/4,0]
wp[2]=[942/4,1608/4,0]



a = wp.map{|wp|{x: wp[0].to_i, y:wp[1].to_i, z:wp[2].to_i}}

wp2 = []
wp2[0]=[7055/4,1124/4,0]
wp2[1]=[704/4,1608/4,0]
wp2[2]=[942/4,1608/4,0]
wp2[3]=[942/4,2107/4,0]

a2 = wp2.map{|wp2|{x: wp2[0].to_i, y:wp2[1].to_i, z:wp2[2].to_i}}



File.open(".../temp.json","w") do |f|
  f.write(a.to_json)
end


File.open(".../temp.json","a+") do |f|
  f.write(a2.to_json)
end

f = open(".../temp.json")
jon  = f.read
#This completes teh writing

psd = JSON.parse(jon)


psd.each do |xo|
  print xo["y"].to_i,"\n"
end

当只在文件中写入一个数组时,它被正确读取,但是当写入第二个数组时,它正确写入,但是出错:

(JSON::ParserError)
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/json/common.rb:155:in `parse'
    from jsont.rb:35:in `<main>'
"The JSON.parse(jon) gives Error."


[{"x":176,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}][{"x":1763,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]

您会注意到在JSON文件中,已连接了两个数组。我知道这是导致错误的。但是我怎样才能纠正它,这样我才能以二维数组的形式访问每个坐标?我以前不知道要写的数组的数量。

3 个答案:

答案 0 :(得分:1)

JSON中的正确数组(甚至数组数组)以[开头,以]开头,每两个项目之间有一个,

因此,以下内容不是有效的JSON:

[1, 2, 3][4, 5, 6]

虽然这是:

[[1, 2, 3], [4, 5, 6]]

要解决您的问题,您可以在一个新行中编写每个数组,然后在读回它们时,您可以逐行读取它们,分别解析每个数组:

File.open(".../temp.json","w") do |f|
  f.puts(a.to_json)
end


File.open(".../temp.json","a+") do |f|
  f.puts(a2.to_json)
end

这将创建一个如下所示的文件:

[{"x":176,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]
[{"x":1763,"y":281,"z":0},{"x":176,"y":402,"z":0},{"x":235,"y":402,"z":0},{"x":235,"y":526,"z":0},{"x":322,"y":526,"z":0},{"x":448,"y":526,"z":0},{"x":508,"y":526,"z":0},{"x":508,"y":640,"z":0},{"x":577,"y":640,"z":0},{"x":577,"y":669,"z":0},{"x":718,"y":669,"z":0}]

您可以稍后阅读:

arrs = File.readlines(".../temp.json").map do |line|
  JSON.parse(line)
end

这应该会产生一个数组数组。

答案 1 :(得分:0)

您正在将一堆连续的JSON字符串写入没有分隔符的文件中。

您的选择是:

  1. 创建所有数组的单个数组,将其转换为JSON并将其写入文件
  2. 将您的JSON字符串与分隔符分开,然后在读取时将它们拆分。使用换行可能最容易做到这一点(例如,将f.write更改为f.puts,然后在每行读取迭代并一次解析每一行。)

答案 2 :(得分:0)

也许这会帮助你学习如何钓鱼......

您不能将JSON输出编写为两个单独的简单写入,并期望解析器能够正确解释数据。 JSON,无论是被美化和写成多行,还是作为单行写成的流,仍然是一个对象,无论是数组还是哈希。两者都必须包裹[ ... ]{ ... },并且延续字符显示有更多元素',',两者都包含这是您在撰写数据时所遗漏的内容。

考虑这段代码及其输出:

require 'json'

a_of_h_1 = [{'a' => 1}, {'b' => 2}]
a_of_h_2 = [{'c' => 3}, {'d' => 4}]

File.open('foo', 'w') do |fo|
  fo.puts JSON[a_of_h_1]
  fo.puts JSON[a_of_h_2]
end

查看shell中的文件,它看起来像这样:

[{"a":1},{"b":2}]
[{"c":3},{"d":4}]

如果我尝试阅读该文件:

JSON[File.read('foo')]

我明白了:

unexpected token at '[{"c":3},{"d":4}] (JSON::ParserError)

那是因为没有包含/包装的分隔符集告诉解析器数据是单个对象的一部分而且不是中间的','告诉解析器那里是附加数据。我可以编写与哈希数组数组相同的数据:

File.open('foo', 'w') do |fo|
  fo.puts JSON[[a_of_h_1, a_of_h_2]]
end

这导致文件看起来像:

[[{"a":1},{"b":2}],[{"c":3},{"d":4}]]

请注意包含[ ... ]和分隔','

现在解析器很满意,并且能够正确检索对象:

(a_a1, a_a2) = JSON[File.read('foo')]
a_a1 # => [{"a"=>1}, {"b"=>2}]
a_a2 # => [{"c"=>3}, {"d"=>4}]

好的,回到你的代码。让解析器为您生成流更容易/更安全/更好。如果你不能这样做,那么你必须知道解析器需要如何查看数据,然后以那种格式创建文件,这并不难。

再次,首先看看生成器使用简单版本的数据结构做什么:

puts JSON[[a_of_h_1, a_of_h_2]]
# >> [[{"a":1},{"b":2}],[{"c":3},{"d":4}]]

很容易弄清楚如何构建文件的格式。我强烈建议让发电机尽可能多地进行繁重的工作,因此我要让它对各个子阵列进行序列化:

a_of_a_of_h = []
a_of_a_of_h << a_of_h_1
a_of_a_of_h << a_of_h_2

File.open('foo', 'w') do |fo|
  fo.puts '['
  a_of_a_of_h[0..-2].each do |a_of_h|
    fo.puts a_of_h.to_json
    fo.puts ','
  end
  fo.puts a_of_a_of_h[-1].to_json
  fo.puts ']'
end

该代码写入开头'[',写入所有子数组并添加','字符,然后重复到倒数第二个元素,然后写入最后一个元素和结束']'。 现在文件看起来像:

[
[{"a":1},{"b":2}]
,
[{"c":3},{"d":4}]
]

它不漂亮但它有效:

JSON[File.read('foo')]
# => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]

如果我清理代码,我会得到:

File.open('foo', 'w') do |fo|
fo.puts '['
fo.puts a_of_a_of_h.map(&:to_json).join(',')
fo.puts ']'
end

map(&:to_json)to_json方法应用于每个子数组,然后join(',')在所有序列化元素之间适当地添加','。重要的是要注意join在最后一个元素之后不添加逗号,就像天真的算法一样。

查看文件:

[
[{"a":1},{"b":2}],[{"c":3},{"d":4}]
]

阅读和重新分析数据:

JSON[File.read('foo')]
# => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]

此时,可以轻松地将传入数据重新分配给变量:

(ary_a, ary_b) = JSON[File.read('foo')]
# => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]
ary_a # => [{"a"=>1}, {"b"=>2}]
ary_b # => [{"c"=>3}, {"d"=>4}]

在我的真实代码中,我写的是:

File.open('foo', 'w') do |fo|
  fo.puts '[', fo.puts a_of_a_of_h.map(&:to_json).join(','), ']'
end

如果由于内存限制或要求而不得不迭代数组。否则我会把它扔到JSON生成器上,然后让它全部咀嚼:

File.write('foo', JSON[a_of_a_of_h])
JSON[File.read('foo')]
# => [[{"a"=>1}, {"b"=>2}], [{"c"=>3}, {"d"=>4}]]