json.loads无法解析nan/infinity,需用object_hook拦截字符串替换或正则预清洗:前者遍历dict键值对将'nan'等转为float('nan'),后者用re.sub替换成null/1e999再转换。

json.loads遇到NaN或Infinity直接报错
Python原生json.loads不接受NaN、Infinity、-Infinity这些JSON非标准值,一碰到就抛json.decoder.JSONDecodeError,错误信息类似Expecting value: line 1 column 18 (char 17)——它卡在第一个非法token上,不会告诉你具体是NaN还是Infinity。
用object_hook预处理字符串再转数值
不能靠parse_float或parse_int解决,因为NaN/Infinity根本不是数字字面量,而是独立token。得在解析中途拦截原始字符串值,手动识别并替换。
- 给
json.loads传object_hook参数,在每个dict解析完成时遍历键值对 - 对每个
str类型的值,用value.strip()后比对是否等于'NaN'、'Infinity'、'-Infinity' - 匹配则转成对应Python对象:
float('nan')、float('inf')、float('-inf') - 注意:只处理顶层string值;嵌套list里的string需额外在
object_hook里递归处理,或改用object_pairs_hook
import json
def handle_nan_inf(obj):
if isinstance(obj, dict):
for k, v in obj.items():
if isinstance(v, str):
s = v.strip()
if s == 'NaN':
obj[k] = float('nan')
elif s == 'Infinity':
obj[k] = float('inf')
elif s == '-Infinity':
obj[k] = float('-inf')
return obj
data = json.loads('{"x": NaN, "y": Infinity}', object_hook=handle_nan_inf)
更稳妥的做法:先用正则预清洗JSON字符串
如果输入源不可控(比如前端JS直接JSON.stringify({a: NaN})),object_hook可能漏掉list里的非法值,且无法处理顶层非object/array的情况(如单个NaN)。这时用正则提前替换更可靠。
基于三引擎设计,从微信文章、新闻和博客网页提取干净内容,支持标题作者日期元数据,多格式和批量处理。
- 用
re.sub把r'\bNaN\b'→'null',r'\bInfinity\b'→'1e999',r'-Infinity'→'-1e999' - 注意
\b防止匹配到"myNaNValue"这种误伤 - 替换后
json.loads能正常解析,再用object_hook或单独遍历把1e999转回float('inf') - 不推荐直接替换成
float('inf').__repr__()结果(如inf),因为JSON规范不认这个,会再次报错
别依赖allow_nan=True——它只控制输出,不解决输入
json.loads根本没有allow_nan参数;那是json.dumps的选项,用来决定是否允许把float('nan')写成NaN字符串。很多人搜“python json allow nan”就误以为输入也能开这个开关,结果白调半天参数。
真正要处理非法输入,只有两条路:预清洗字符串,或用object_hook+类型判断。前者健壮,后者轻量——选哪个取决于你是否信任数据结构深度和一致性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










