解析多JSON文件时字符索引不一致问题及正确解析方案咨询
问题:解析逗号分隔的多行JSON对象时后续对象失败的原因与解决方法
我用以下Python代码解析存储在.json文件里的逗号分隔多行JSON对象(数据来自网页抓取):
import json def stream_read_json(fn): start_pos = 0 with open(fn, 'r', encoding='utf-8') as f: while True: try: obj = json.load(f) yield obj return except json.JSONDecodeError as e: f.seek(start_pos) json_str = f.read(e.pos) obj = json.loads(json_str, encoding = 'utf-8') start_pos += e.pos yield obj
第一个对象可正常解析,但后续对象无法解析。调试时发现,JSONDecodeError抛出的e.pos与IDE中选中的JSON对象结束位置的字符索引存在差异,测试时第二个JSON对象对应的f.seek(start_pos)值与报错的e.pos差异明显。以下是示例JSON:
{ "user": { "id": 1, "profile": { "name": "Alice", "age": 30 } }, "product": { "sku": "A1234", "details": { "name": "Laptop", "price": 999.99 } } }, { "user": { "id": 2, "profile": { "name": "Bob", "age": 22 } }, "product": { "sku": "A123w", "details": { "name": "Laptop", "price": 9.99 } } }
差异产生的原因
- 字节位置与字符索引不匹配:
json.load()内部会处理换行符(比如将Windows的\r\n转为\n),但文件的seek操作是按字节位置计算的,而IDE显示的字符索引是按文本字符数统计的,换行符的字节长度差异会导致两者数值不一致。 - 解析位置逻辑错误:
e.pos是json.load()尝试解析时的错误位置(基于它的内部缓冲区),并非文件的实际字节位置。你用f.seek(start_pos)后读取e.pos个字符,会导致start_pos累加错误,后续读取的起始位置完全偏离。 - 未处理分隔逗号:第一个JSON对象解析完成后,文件中剩余的逗号和换行符没有被跳过,后续解析从逗号开始,直接触发JSONDecodeError。
正确解析的解决方法
方法1:逐行缓存+raw_decode精准解析
使用json.JSONDecoder().raw_decode()方法,它会返回解析后的对象和解析到的索引位置,能准确截取剩余内容并跳过分隔符:
import json def stream_read_json(fn): with open(fn, 'r', encoding='utf-8') as f: buffer = '' for line in f: buffer += line.strip() try: # 解析buffer中的第一个完整JSON对象,返回对象和结束索引 obj, end_idx = json.JSONDecoder().raw_decode(buffer) yield obj # 移除已解析的部分,跳过逗号和空白字符 buffer = buffer[end_idx:].lstrip(', \n\r') except json.JSONDecodeError: # 内容不完整,继续读取下一行 continue
方法2:转换为JSON数组批量解析
如果文件体积不大,直接给内容包裹成JSON数组,利用标准JSON解析逻辑一次性处理:
import json def read_json_objects(fn): with open(fn, 'r', encoding='utf-8') as f: content = f.read().strip() # 将逗号分隔的对象转为合法的JSON数组 json_array = f'[{content}]' objects = json.loads(json_array) for obj in objects: yield obj
内容的提问来源于stack exchange,提问作者Martin Horst
相关产品推荐
相关产品推荐

