【问题标题】:Extracting individual JSON objects提取单个 JSON 对象
【发布时间】:2016-07-05 11:08:37
【问题描述】:

我有以下从 API 获取的 JSON 文件。

{"Key-1":"Value-1",
"Key-2":[{"Value-2"::Child_Value-1","Value-3":"Child_Value-2"}]
}
{"Key-21":"Value-21",
"Key-22":[{"Value-22":"Child_Value-21","Value-23":"Child_Value-22"}]
}
{"Key-31":"Value-31",
"Key-32":[{"Value-32":"Child_Value-31","Value-33":"Child_Value-32"}]
}

我知道这不符合 JSON 格式,但我想要实现的是我想提取每个单独的对象并将它们存储在一个单独的文件中。

例如file1.json 应该包含 -

[{"Key-1":"Value-1",
    "Key-2":[{"Value-2":"Child_Value-1","Value-3":"Child_Value-2"}]
    }]

file2.json 应该包含 -

[{"Key-21":"Value-21",
    "Key-22":[{"Value-22":"Child_Value-21","Value-23":"Child_Value-22"}]
    }]

我正在尝试通过 python 和 shell 脚本来执行此操作,但它并没有引导我到任何地方。 python/shell中是否有一个很好的库可以提供帮助。我有点限制要使用的语言(python,shell-script)

【问题讨论】:

标签: python json bash shell unix


【解决方案1】:

这里有一些东西会非常慢并且无法处理数据中的错误,但它可能会起作用。它是一个生成器,它找到第一个“{”,然后找到下一个“}”,并尝试将其间的位解析为 JSON。如果失败,它会寻找下一个 '}' 并再次尝试。它产生成功解析的位。

import json

def generate_json_dictionaries(s):
    opening = s.find('{')
    while opening != -1:
        possible_closing = opening
        while True:
            possible_closing = s.find('}', start=possible_closing+1)
            if possible_closing == -1: return  # Data incomplete
            try:
                j = json.loads(s[opening:possible_closing+1])
                yield j
                break
            except ValueError:
                pass
        opening = s.find('{', start=possible_closing+1)  # Next start

未测试。

【讨论】:

    【解决方案2】:

    这正是您的问题所要求的(尽管我怀疑这实际上不是您想要的)

    filecount = 0
    newfilecontents = ''
    
    with open('junksrc.txt', mode='r', encoding='utf-8') as src:
        srclines = src.readlines()
        for line in srclines:
            if '{"Key' in line:
                newfilecontents = '[' + line
            if '}]' in line:
                newfilecontents = newfilecontents + '    ' + line + '    }]\n'
                filecount += 1
                filename = 'junkdest' + str(filecount) + '.json'
                with open(filename, mode='w', encoding='utf-8') as dest:
                    dest.write(newfilecontents)
    

    【讨论】:

      【解决方案3】:

      如果你得到jq,你可以将你的数据预处理成一个易于被标准库的 JSON 解析器解析的表单:

      $ jq -s '.' tmp.json
      [
        {
          "Key-1": "Value-1",
          "Key-2": [
            {
              "Value-2": "Child_Value-1",
              "Value-3": "Child_Value-2"
            }
          ]
        },
        {
          "Key-21": "Value-21",
          "Key-22": [
            {
              "Value-22": "Child_Value-21",
              "Value-23": "Child_Value-22"
            }
          ]
        },
        {
          "Key-31": "Value-31",
          "Key-32": [
            {
              "Value-32": "Child_Value-31",
              "Value-33": "Child_Value-32"
            }
          ]
        }
      ]
      

      jq 可以识别有效的顶级对象流,就像您在此处一样。 -s 选项告诉jq 在进一步处理之前将它们全部放在一个顶级数组中。

      【讨论】:

      • 这很有帮助。谢谢!有没有办法给你用 jq 命令创建的数组命名? jq 是否有一些额外的功能来进行这样的操作?
      • 我不确定您所说的“给 [它] 起个名字”是什么意思。使用它的一种方法是将其通过管道传输到您的 Python 脚本中,并使用 json.load 从标准输入中读取:jq -s . tmp.json | python -c 'import sys,json; x = json.load(sys.stdin); ...'
      • 我所说的命名数组的意思是您使用 jq -s 命令创建的数组 - “单个顶级数组”。您提供的示例创建了一个没有名称的顶级数组。我想知道是否有使用名称创建的选项。
      • 数组在 JSON 中没有名称,我之前评论中的 sn-p 为解析的字符串分配了一个 Python 名称。你想要一个shell参数吗? x=$(jq -s '.' tmp.json)
      猜你喜欢
      • 1970-01-01
      • 2018-09-22
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多