在python中导入错误连接的JSON

时间:2016-03-15 19:02:16

标签: python json regex

我有一个文本文档,其中有几千个jsons字符串,格式为:"{...}{...}{...}"。这不是一个有效的json,而是每个{...}

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

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

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

问题在于,很少有tags属性写为"{tagName1}{tagName2}",这会破坏我的正则表达式。

一个例子是:

'{"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解析实现这个的正确方法是什么?

3 个答案:

答案 0 :(得分:4)

使用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语法错误。

使用一个非常长的短元素文件,你可以将一个块读入一个缓冲区并应用上面的循环,在循环中断后将剩下的任何内容与下一个块连接起来。

答案 1 :(得分: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模式。

答案 2 :(得分:1)

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

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编写一个更复杂的解析器或其他一些语法库(有效地编写自己的语言解析器)