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

时间:2012-01-04 16:19:39

标签: python json object

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

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

并且在文本文件中没有分隔符的情况下连接数百个这样的对象。这意味着我既不能使用json.load()也不能使用json.loads()

有关如何解决此问题的任何建议。是否有一个已知的解析器来执行此操作?

9 个答案:

答案 0 :(得分:22)

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

答案 1 :(得分:4)

塞巴斯蒂安·布拉斯克有正确的想法,但没有理由使用正则表达式进行这么简单的改变。

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

答案 2 :(得分:3)

解决方案

据我所知}{没有出现在有效的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对象。请参见此处的证据: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中得到证实。

答案 3 :(得分:3)

这样的事情怎么样:

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 )

答案 4 :(得分:2)

为什么不将文件作为字符串加载,替换所有} {with},{并用[]包围整个文件?类似的东西:

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

或者简单的字符串替换,如果你确定你总是有{}之间没有空格。

如果您希望} {也出现在字符串中,您也可以拆分} {并使用json.load评估每个片段,以防您收到错误,片段未完成且您必须添加在第一个旁边等等。

答案 5 :(得分:1)

每次找到{时,通过文件递增计数器怎么样,当遇到{时,递减计数器}。当你的计数器达到0时,你就会知道你已经到了第一个对象的末尾,所以通过json.load发送它并重新开始计数。然后重复完成。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

用其中的垃圾替换文件:

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

在Python中动态执行:

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