【问题标题】:Importing wrongly concatenated JSONs in python在 python 中导入错误连接的 JSON
【发布时间】:2016-03-15 19:02:16
【问题描述】:

我有一个包含数千个 jsons 字符串的文本文档,格式为:"{...}{...}{...}"。这不是它自己的有效 json,但每个 {...} 都是。

我目前使用以下正则表达式来拆分它们:

fp = open('my_file.txt', 'r')
raw_dataset = (re.sub('}{', '}\n{', fp.read())).split('\n')

这基本上打破了花括号关闭和其他打开的每一行 (}{ -> }\n{),因此我可以将它们分成不同的行。

问题是它们中很少有人有写成"{tagName1}{tagName2}"tags 属性,这会破坏我的正则表达式。

一个例子是:

'{"name":\"Bob Dylan\", "tags":"{Artist}{Singer}"}{"name": "Michael Jackson"}'

被解析成

'{"name":"Bob Dylan", "tags":"{Artist}'
'{Singer}"}'
'{"name": "Michael Jackson"}'

而不是

'{"name":"Bob Dylan", "tags":"{Artist}{Singer}"}'
'{"name": "Michael Jackson"}'

为进一步解析 json 实现这一点的正确方法是什么?

【问题讨论】:

  • { name : "foo" } 也不是 json。 { "name" : "foo" } 是 json。注意双引号。
  • 每个{}中的数据格式是否相同?我的意思是每个数据都以{name 开头吗?
  • @hek2mgl 你是对的,我只是修复它们
  • @noob 不一定。
  • @fuxes:你能发布更多数据吗?

标签: python json regex


【解决方案1】:

使用json.JSONDecoder的raw_decode方法

>>> import json
>>> d = json.JSONDecoder()
>>> x='{"name":\"Bob Dylan\", "tags":"{Artist}{Singer}"}{"name": "Michael Jackson"}'
>>> d.raw_decode(x)
({'tags': '{Artist}{Singer}', 'name': 'Bob Dylan'}, 47)
>>> x=x[47:]
>>> d.raw_decode(x)
({'name': 'Michael Jackson'}, 27)

raw_decode 返回一个 2 元组,第一个元素是解码后的 JSON,第二个元素是 JSON 结束后下一个字节的字符串中的偏移量。

循环直到结束或遇到无效的 JSON 元素:

>>> while True:
...   try:
...     j,n = d.raw_decode(x)
...   except ValueError:
...     break
...   print(j)
...   x=x[n:]
... 
{'name': 'Bob Dylan', 'tags': '{Artist}{Singer}'}
{'name': 'Michael Jackson'}

当循环中断时,检查 x 将显示它是否处理了整个字符串或遇到了 JSON 语法错误。

对于一个非常长的短元素文件,您可能会将一个块读入缓冲区并应用上述循环,将循环中断后剩余的任何内容与下一个块连接起来。

【讨论】:

  • 这是一个很好的方法,效果很好,但是对于计算大文件来说太慢了。
  • 空字符串不是有效的 JSON。抓住异常......我正在添加我的答案
  • 你可以在字符串不为空的情况下进行简单的迭代
  • 我最终用我的正则表达式解析文件并保存它被破坏的地方。然后根据您的回答,我能够加入字符串的这些部分并再次解析 json。
【解决方案2】:

您可以使用jq 命令行实用程序将您的输入传输到 json。假设您有以下输入:

input.txt:

{"name":"Bob Dylan", "tags":"{Artist}{Singer}"}{"name": "Michael Jackson"}

您可以使用jq -s,它使用来自输入的多个json文档并将它们传输到单个输出数组中:

jq -s . input.txt

给你:

[
  {
    "name": "Bob Dylan",
    "tags": "{Artist}{Singer}"
  },
  {
    "name": "Michael Jackson"
  }
]

我刚刚意识到libjq 有 python 绑定。意思是你 不需要使用命令行,可以直接在python中使用jq

https://github.com/mwilliamson/jq.py

但是,到目前为止,我还没有尝试过。让我试一试:) ...

更新:上面的库不错,但目前还不支持 slurp 模式。

【讨论】:

    【解决方案3】:

    你需要做一个解析器......我不认为正则表达式可以帮助你

    data = ""
    curlies = []
    def get_dicts(file_text):
        for letter in file_text:
            data += letter
            if letter == "{":
               curlies.append(letter)
            elif letter == "}":
               curlies.pop() # remove last
               if not curlies:
                  yield json.loads(data)
                  data = ""
    

    注意,这实际上并不能解决{name:"bob"}不是有效json的问题...{"name":"bob"}

    如果字符串中有奇怪的不平衡括号,这也会中断,即{"name":"{{}}}"} 会中断

    真的,根据您的示例,您的 json 是如此损坏,您最好的选择可能是手动编辑它并修复生成它的代码......如果这不可行,您可能需要使用 pylex 编写更复杂的解析器或其他一些语法库(有效地编写自己的语言解析器)

    【讨论】:

    • 但是如果字符串中有一个“}”呢?您不能只说“当引号计数不为零时,我们还将计算引号并忽略卷曲”,因为如果字符串中有转义引号怎么办?您不能只说“如果前一个字符是反斜杠,我们不会将引号计入引号计数”,因为如果字符串中有一个转义的反斜杠,后跟终止该字符串的实际引号怎么办?跨度>
    • 公平点......只要字符串中的卷曲是平衡的,尽管这仍然可以工作(如果它只是随机的卷曲,它肯定会破坏......)
    • 只要使用 json.JSONDecoder 的 raw_decode 方法即可。看我的回答。
    猜你喜欢
    • 2016-06-08
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多