python 如何从一个文本文件中检索多个JSON对象,其中对象不是由分隔符分隔的?

42fyovps  于 2023-03-21  发布在  Python
关注(0)|答案(9)|浏览(357)

我有数千个包含多个JSON对象的文本文件,但不幸的是,对象之间没有分隔符。
对象以字典的形式存储,它们的一些字段本身就是对象。每个对象可能有不同数量的嵌套对象。具体地说,一个对象可能如下所示:

{field1: {}, field2: "some value", field3: {}, ...}

并且数百个这样的对象在文本文件中没有分隔符地连接在一起。这意味着我既不能使用json.load(),也不能使用json.loads()
有什么建议可以解决这个问题吗?有没有已知的解析器可以解决这个问题?

dfddblmv

dfddblmv1#

这将从字符串中解码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)

清洗液(后补)

import json
import re

#shameless copy paste from json/decoder.py
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)

class ConcatJSONDecoder(json.JSONDecoder):
    def decode(self, s, _w=WHITESPACE.match):
        s_len = len(s)

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

示例

>>> 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)
afdcj2ne

afdcj2ne2#

溶液
据我所知,}{不会出现在有效的JSON中,所以当试图为连接的单独对象获取字符串时,下面的内容应该是完全安全的(txt是文件的内容)。它不需要任何导入(即使是re模块)来做到这一点:

retrieved_strings = map(lambda x: '{'+x+'}', txt.strip('{}').split('}{'))

或者如果你更喜欢列表解析(正如大卫Zwicker在评论中提到的),你可以这样使用它:

retrieved_strings = ['{'+x+'}' for x in txt.strip('{}').split('}{'))]

这将导致retrieved_strings是一个字符串列表,每个字符串包含单独的JSON对象。请参见这里的证明:http://ideone.com/Purpb

示例

以下字符串:

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

会变成:

['{field1:"a",field2:"b"}', '{field1:"c",field2:"d"}', '{field1:"e",field2:"f"}']

如在the example I mentioned中证明的。

qlvxas9a

qlvxas9a3#

Sebastian Blask's answer的想法是正确的,但是没有理由使用正则表达式来进行如此简单的更改。

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
f4t66c6m

f4t66c6m4#

不如这样:

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 )
3phpmpom

3phpmpom5#

你可以把文件作为一个字符串加载,用},{替换所有的}{,然后用[]包围整个文件。
比如:

re.sub('\}\s*?\{', '\}, \{', string_read_from_a_file)

如果您确定始终使用}{,而中间没有空格,则可以使用简单的字符串替换。
如果你希望}{也出现在字符串中,你也可以在}{上进行分割,并用json.load计算每个片段,如果你得到一个错误,这个片段不完整,你必须将下一个添加到第一个片段上,依此类推。

bvn4nwqk

bvn4nwqk6#

如何阅读文件,每次找到{时递增计数器,遇到}时递减计数器。当计数器达到0时,您将知道您已经到达第一个对象的末尾,因此通过json.load发送它并重新开始计数。然后重复完成。

33qvvth1

33qvvth17#

import json

file1 = open('filepath', 'r')
data = file1.readlines()

for line in data :
   values = json.loads(line)

'''Now you can access all the objects using values.get('key') '''
bxpogfeg

bxpogfeg8#

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

idfiyjo8

idfiyjo89#

用垃圾文件替换文件:

$ sed -i -e 's;}{;}, {;g' foo

在Python中动态执行:

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

相关问题