如何解决JSON空键值缺省触发的JSONDecodeError解析报错问题
解析字符串列表转JSON的场景下,两类返回结果的表现如下:
- 列表含有效元素时,返回结构为:
{'body': '{"A":"a", "B": ["abc"], "C":"c"}'}
按顺序调用json.dumps、json.loads即可完成正常解析。
- 列表为空时,对接平台返回非法JSON格式,结构为:
{'body': '{"A":"a", "B": , "C": "c"}'}
直接解析会抛出JSONDecodeError: Expecting value异常,无法读取B键对应值。
当前使用的B键取值逻辑为:
B_key = [] if body.get("B", []) == "" else json.dumps(body.get("B", []))
已知符合JSON规范的B键合法取值为"B": ""或"B": [],但对接平台固定返回值缺省的非法格式,需要可落地的适配方案。
按适配成本从低到高、鲁棒性从强到弱排序:
方案1:正则预修复非法片段(优先推荐)
在执行JSON解析前,对原始待解析字符串做定向替换,把缺省值的键值对补全为符合业务预期的默认值。
如果仅B键会出现缺省问题,直接定向匹配修复即可:
import re import json # 假设已经从外层结构提取到待解析的内层JSON字符串 raw_json_str = '{"A":"a", "B": , "C": "c"}' # 匹配"B": 后直接跟逗号/结束符的场景,补全为空数组 fixed_json_str = re.sub(r'("B"\s*:\s*)(,|})', r'\1[]\2', raw_json_str) # 后续正常执行解析流程 parsed_data = json.loads(fixed_json_str)
如果多个键都可能出现值缺省的问题,可以用通用正则统一补全默认值(比如补null,后续业务层再做兜底):
# 匹配所有"键名": 后直接跟逗号/结束符的场景,统一补null fixed_json_str = re.sub(r'("[a-zA-Z0-9_]+"\s*:\s*)(,|})', r'\1null\2', raw_json_str)
该方案不需要引入额外依赖,性能开销极低,只要正则规则匹配准确即可覆盖所有已知异常场景。
方案2:使用容错JSON解析库
如果平台返回的非法格式场景较多,不想逐个维护正则规则,可以引入支持非标准JSON解析的库做兼容,比如json5、demjson,这类库可自动兼容值缺省、尾逗号、单引号、注释等常见JSON语法错误。
以json5为例:
import json5 raw_json_str = '{"A":"a", "B": , "C": "c"}' parsed_data = json5.loads(raw_json_str) # 解析后缺省的B键值为None,业务层直接做兜底即可 B_key = parsed_data.get("B", [])
注意:该方案需要引入第三方依赖,生产环境使用前需评估库的维护状态、安全风险与性能表现。
方案3:异常捕获定向兜底
如果缺省场景固定、出现频率极低,可以在解析逻辑外层加异常捕获,触发解析错误时手动替换异常片段后再解析:
import json raw_json_str = '{"A":"a", "B": , "C": "c"}' try: parsed_data = json.loads(raw_json_str) except json.JSONDecodeError: fixed_str = raw_json_str.replace('"B": ,', '"B": []') parsed_data = json.loads(fixed_str)
该方案鲁棒性最差,平台返回格式稍有变动就会失效,仅建议作为临时兜底方案使用。
适配逻辑上线前必须加单元测试,同时覆盖正常返回、空列表返回两类场景,避免后续平台格式调整导致解析逻辑故障。
内容的提问来源于stack exchange,提问作者Kit

