在真实世界的数据处理中,我们很少遇到教科书式的标准 json。更多时候,面对的是:
- 单引号代替双引号
- 末尾多出逗号
- 键名未加引号(如
{name: "alice"}) - 混合了注释(
// 这是注释) - 嵌套结构缺失或类型错乱(字符串里藏了 json 片段)
- 甚至根本不是合法 json,而是 javascript 对象字面量(js object literal)
这类“不规则 json”无法被 python 内置的 json.loads() 直接解析,强行使用会抛出 jsondecodeerror。但别急——本文将为你提供一套从温和修复到强力解析的完整工具箱,用 python 轻松驯服这些“野性”数据。
一、场景1:轻微格式错误(单引号、尾逗号等)
典型数据:
{
'name': 'alice',
'age': 30,
'tags': ['a', 'b',],
}
解法:使用ast.literal_eval(仅限 python 字面量)
如果数据本质是 python 字典/列表字面量(而非严格 json),可尝试:
import ast
dirty_str = "{'name': 'alice', 'age': 30, 'tags': ['a', 'b',]}"
try:
data = ast.literal_eval(dirty_str)
print(data) # {'name': 'alice', 'age': 30, 'tags': ['a', 'b']}
except (valueerror, syntaxerror) as e:
print("无法解析为 python 字面量")
注意:ast.literal_eval 只支持 str, bytes, int, float, list, dict, tuple, bool, none,不支持 nan、infinity 等。
二、场景2:含注释、尾逗号、键无引号(类 js 对象)
典型数据:
{
// 用户信息
name: "bob",
age: 25,
hobbies: [
"coding",
"gaming", // 末尾逗号
],
}
解法:使用json5库(推荐!)
json5 是 json 的扩展,支持注释、单引号、尾逗号、无引号键等,完美兼容 javascript 风格对象。
安装:
pip install json5
使用:
import json5
with open('config.js', 'r', encoding='utf-8') as f:
data = json5.load(f) # 或 json5.loads(string)
print(data['name']) # bob
优点:安全、标准、广泛用于前端配置文件(如 .babelrc, tsconfig.json 变体)。
三、场景3:字符串中嵌套未转义的 json 片段
典型数据:
{
"log": "user {"id": 123, "action": "login"} performed"
}
你可能想提取内部的 {"id": 123, ...},但它被包裹在字符串中。
解法:正则 + 递归解析
import json
import re
def extract_and_parse_nested_json(text):
# 匹配最外层的 {...},但需确保是完整 json 对象
pattern = r'{(?:[^{}]|(?r))*}' # 递归正则(python 不支持 (?r),改用循环)
# 更稳健的做法:逐字符扫描括号匹配
def find_outer_braces(s):
stack = 0
start = -1
for i, c in enumerate(s):
if c == '{':
if stack == 0:
start = i
stack += 1
elif c == '}':
stack -= 1
if stack == 0 and start != -1:
return s[start:i+1]
return none
nested = find_outer_braces(text)
if nested:
try:
return json.loads(nested)
except json.jsondecodeerror:
return none
return none
log_str = 'user {"id": 123, "action": "login"} performed'
inner = extract_and_parse_nested_json(log_str)
print(inner) # {'id': 123, 'action': 'login'}
四、场景4:完全非结构化,但有规律可循
比如日志文件中的混合内容:
info: {user: "tom", status: ok}
error: failed to parse {data: [1,2,,3]}
解法:先用正则提取疑似 json 片段,再用容错解析器
结合 json5 + 异常捕获:
import json5
import re
log_line = 'error: failed to parse {data: [1,2,,3]}'
# 提取花括号包围的内容
match = re.search(r'{.*}', log_line)
if match:
candidate = match.group()
try:
data = json5.loads(candidate)
print("parsed:", data)
except exception as e:
print("still invalid:", e)
提示:对于 [, ,] 这类空元素,json5 也支持(视为 null)。
五、终极武器:自定义解析器 or llm 辅助(慎用)
若数据极度混乱(如混合 html、自定义 dsl),可考虑:
- 使用
lark、ply构建自定义语法解析器; - 用大模型(如本地 llm)将“脏数据”重写为合法 json(适合低频、高价值场景)。
但绝大多数情况,json5 + 正则清洗 + 异常处理 已足够覆盖。
最佳实践建议
- 优先用
json5:它能解决 90% 的“类 json”问题; - 不要用
eval():极其危险,可能执行任意代码; - 记录解析失败样本:用于后续规则优化;
- 在数据入口 做标准化:若可控,推动上游输出合法 json。
结语
不规则 json 不是“错误”,而是现实世界的常态。python 生态提供了从轻量级(ast)到工业级(json5)的多种工具,关键在于识别数据“脏”在哪一层,然后选择匹配的清洗策略。
记住:解析不是目的,可靠地获取结构化信息才是。用对工具,那些看似混乱的字符串,终将成为你数据管道中的清晰字段。
到此这篇关于python解析不规则json数据的实战技巧的文章就介绍到这了,更多相关python解析json数据内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论