从文本文件检索JSON对象(使用Python)

从文本文件检索JSON对象(使用Python),python,json,object,Python,Json,Object,我有数千个包含多个JSON对象的文本文件,但不幸的是,这些对象之间没有分隔符。对象存储为字典,其中一些字段本身就是对象。每个对象可能具有数量可变的嵌套对象。具体而言,对象可能如下所示: {field1: {}, field2: "some value", field3: {}, ...} import re import json jsonstr = open('test.json').read() p = re.compile( '}\s*{' ) jsonstr = p.sub( '

我有数千个包含多个JSON对象的文本文件,但不幸的是,这些对象之间没有分隔符。对象存储为字典,其中一些字段本身就是对象。每个对象可能具有数量可变的嵌套对象。具体而言,对象可能如下所示:

{field1: {}, field2: "some value", field3: {}, ...} 
import re
import json

jsonstr = open('test.json').read()

p = re.compile( '}\s*{' )
jsonstr = p.sub( '}\n{', jsonstr )

jsonarr = jsonstr.split( '\n' )

for jsonstr in jsonarr:
   jsonobj = json.loads( jsonstr )
   print json.dumps( jsonobj )
数百个这样的对象在文本文件中没有分隔符而被连接在一起。这意味着我既不能使用
json.load()
也不能使用
json.load()


关于我如何解决这个问题的任何建议。有一个已知的解析器可以做到这一点吗?

假设您在文件文本的开头添加了一个[a],并使用了一个版本的json.load(),当它检测到查找{而不是预期的逗号(或到达文件的末尾)的错误时,抛出刚刚完成的对象?

为什么不将文件作为字符串加载,将所有}{替换为},{然后用[]环绕整个东西?类似于:

re.sub('\}\s*?\{', '\}, \{', string_read_from_a_file)
或者简单的字符串替换,如果您确定在}{之间总是没有空格的话


如果您希望}{也出现在字符串中,您也可以在}{上拆分,并使用json.load计算每个片段,如果出现错误,该片段不完整,您必须将下一个片段添加到第一个片段中,以此类推。

每次读取一个计数器时,读取该文件如何{被找到,当你遇到一个}时,它将递减。当你的计数器达到0时,你将知道你已经到达了第一个对象的末尾,所以通过json.load发送它并再次开始计数。然后重复直到完成。

据我所知,
}{
没有出现在有效的JSON中,因此,当尝试获取连接的单独对象的字符串时,以下内容应该是完全安全的(
txt
是您文件的内容)。它不需要任何导入(即使是
re
模块)来完成此操作:

retrieved_strings = map(lambda x: '{'+x+'}', txt.strip('{}').split('}{'))
或者,如果您喜欢列表理解(如David Zwicker在评论中提到的),您可以这样使用它:

retrieved_strings = ['{'+x+'}' for x in txt.strip('{}').split('}{'))]
它将导致
retrieved_strings
成为一个字符串列表,每个字符串包含单独的JSON对象。请参见此处的证明:

例子 以下字符串:

'{field1:"a",field2:"b"}{field1:"c",field2:"d"}{field1:"e",field2:"f"}'
将变成:

['{field1:"a",field2:"b"}', '{field1:"c",field2:"d"}', '{field1:"e",field2:"f"}']
如中所述。

这将从字符串中解码JSON对象的“列表”:

from json import JSONDecoder

def loads_invalid_obj_list(s):
    decoder = JSONDecoder()
    s_len = len(s)

    objs = []
    end = 0
    while end != s_len:
        obj, end = decoder.raw_decode(s, idx=end)
        objs.append(obj)

    return objs
这里的好处是,您可以很好地使用解析器,因此它会不断准确地告诉您在哪里发现了错误

示例

>>> loads_invalid_obj_list('{}{}')
[{}, {}]

>>> loads_invalid_obj_list('{}{\n}{')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "decode.py", line 9, in loads_invalid_obj_list
    obj, end = decoder.raw_decode(s, idx=end)
  File     "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 376, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Expecting object: line 2 column 2 (char 5)
>>> print json.loads('{}', cls=ConcatJSONDecoder)
[{}]

>>> print json.load(open('file'), cls=ConcatJSONDecoder)
[{}]

>>> print json.loads('{}{} {', cls=ConcatJSONDecoder)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 339, in loads
    return cls(encoding=encoding, **kw).decode(s)
  File "decode.py", line 15, in decode
    obj, end = self.raw_decode(s, idx=_w(s, end).end())
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 376, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Expecting object: line 1 column 5 (char 5)
示例

>>> loads_invalid_obj_list('{}{}')
[{}, {}]

>>> loads_invalid_obj_list('{}{\n}{')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "decode.py", line 9, in loads_invalid_obj_list
    obj, end = decoder.raw_decode(s, idx=end)
  File     "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 376, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Expecting object: line 2 column 2 (char 5)
>>> print json.loads('{}', cls=ConcatJSONDecoder)
[{}]

>>> print json.load(open('file'), cls=ConcatJSONDecoder)
[{}]

>>> print json.loads('{}{} {', cls=ConcatJSONDecoder)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 339, in loads
    return cls(encoding=encoding, **kw).decode(s)
  File "decode.py", line 15, in decode
    obj, end = self.raw_decode(s, idx=_w(s, end).end())
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 376, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Expecting object: line 1 column 5 (char 5)
打印json.loads(“{}”,cls=ConcatJSONDecoder) [{}] >>>打印json.load(打开('file'),cls=ConcatJSONDecoder) [{}] >>>print json.load('{}{}{',cls=ConcatJSONDecoder) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/_init__.py”,第339行,在loads中 返回cls(编码=编码,**千瓦)。解码 文件“decode.py”,第15行,在decode中 obj,end=self.raw\u decode(s,idx=\u w(s,end.end()) 文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py”,第376行,原始解码 obj,end=self.scan_一次(s,idx) ValueError:应为对象:第1行第5列(字符5)
像这样的东西怎么样:

{field1: {}, field2: "some value", field3: {}, ...} 
import re
import json

jsonstr = open('test.json').read()

p = re.compile( '}\s*{' )
jsonstr = p.sub( '}\n{', jsonstr )

jsonarr = jsonstr.split( '\n' )

for jsonstr in jsonarr:
   jsonobj = json.loads( jsonstr )
   print json.dumps( jsonobj )

塞巴斯蒂安·布拉斯克(Sebastian Blask)的想法是正确的,但没有理由使用正则表达式进行如此简单的更改

objs = json.loads("[%s]"%(open('your_file.name').read().replace('}{', '},{')))
或者,更清楚地说

raw_objs_string = open('your_file.name').read() #read in raw data
raw_objs_string = raw_objs_string.replace('}{', '},{') #insert a comma between each object
objs_string = '[%s]'%(raw_objs_string) #wrap in a list, to make valid json
objs = json.loads(objs_string) #parse json

将文件替换为其中的垃圾文件:

$sed-i-e's;}{;},{;g'foo
在Python中动态执行此操作:

junkJson.replace('}{', '}, {')

它们是否至少被分隔到不同的行上,或者只是一个长的单行
{…}{…}{…}
pileup?不,这就是问题所在,它只是一个长的单行。您可以使用
str.replace
添加分隔符吗?如:
single_line_json.replace('}{,}\n{)
如果您需要更快的解决方案,可以通过切换到生成器来避免大型对象列表:
while end!=s_len:obj,end=decoder.raw_decode(s,idx=end)yield obj
。哦,我明白你的意思了。你是否建议在列索引显示时使用try/except然后拆分?我很快尝试了一下,得到了一个异常:“预期,分隔符:第1行第1332列(char 1332)。这是可行的。我只是希望有一个解析器在那里,因为这似乎是可能发生的事情。但是谢谢你的建议。酷!这很聪明而且很容易做到。我会尝试一下,然后返回结果。谢谢!如果你在其他地方有}{字符串,比如属性值,会怎么样?例如:
{”field1“:”{123”,“field2:“{123”}'
这应该使用列表理解
在txt.strip({}')中为x检索字符串=[{'+x+'}'。split('}{')]
@DavidZwicker:为什么?你是
map()的支持者之一吗
函数被认为已弃用?它是完全有效的。但是它看起来可能更简单,我将把它添加到我的答案中。带
}{
{“f1”:“}{{}{”,“b”:“{{{}{}{{}}}}{{{}}}}“
@Tadeck:See以获取关于map与list comprehension的讨论。实际上,我自己有时使用
map
,但仅在函数已经存在的情况下使用。将
lambda
map
结合使用对我来说没有多大意义。@soulcheck:+1,非常好的一点!它仍然可以解决,但现在需要正在检查
}{
序列是否出现在引号中…真的很酷,我希望json模块会有这样的东西,而且它已经有了。太完美了。谢谢!