Python2.7:如何解码JSON但不解码其中的UTF-8内容?
我需要一个函数来解码UTF-8编码的JSON,该函数需接收UTF-8编码的JSON字符串并将其转换为UTF-8编码的对象。目前我用以下代码实现,但这种做法相当荒谬——json.loads先解码UTF-8,之后我又要重新编码:
# helper function def Obj_To_UTF8(o): res = {} for k, v in o.items(): k = k.encode('utf-8') v = v.encode('utf-8') if isinstance(v, unicode) else v res[k] = v return res # Load UTF-8 encoded JSON to UTF-8 encoded objects def Load_JSON(s): return json.loads(s, object_hook = Obj_To_UTF8)
背景
我需要强调的是,该JSON已采用UTF-8编码。这一点十分重要,因为我希望使用处理文件、套接字等的字节级函数,以与编码后JSON完全相同的字符编码处理解码后的JSON。因此,为实现最佳模块化,程序中不应引入unicode类型。(只有在需要转换编码、编写文本编辑器或字体渲染器这类场景时,才需要引入unicode类型;若无需这些操作,unicode类型及相关编解码操作只会带来麻烦,上述示例就是很好的证明。)
对于不熟悉UTF-8的人来说,它支持直接对字节进行匹配和分词,因此可兼容与编码无关的软件(其中部分软件已有50多年历史仍在使用)。C和Python2等语言可轻松直接处理字节字符串,从而避免频繁的编解码操作。
遗憾的是,json.loads似乎违背了这些原则,且无明显合理理由。我认为JSON实现关注字符编码的原因仅有两个:
- \u特性,该特性是可选的(浏览器默认关闭,因此它们通常会为非ASCII字符生成UTF-8序列)。
- 验证接收的字符串是否为合法的UTF-8格式。希望这种严谨性也是可选的。(除UTF-8强制要求外,JSON的实际分隔方案完全适用于二进制数据。)
因此,JSON实现或许会关注字符编码,但强制所有JSON应用处理字符编码是模块化设计的缺陷:它未实现关注点分离,而是不必要地将JSON解码与UTF-8解码绑定在一起。一个良好的JSON实现至少应提供禁用UTF-8解码的方式。
解决方案
方法1:使用simplejson库的encoding=None参数
simplejson(功能比标准库json更灵活)支持encoding=None选项,设置该参数后,解析后的字符串会保留为原始的UTF-8字节串,不会被解码为unicode类型:
先安装依赖:
pip install simplejson
使用示例:
import simplejson as json def Load_JSON(s): # encoding=None 让解析后的字符串保持UTF-8字节格式 return json.loads(s, encoding=None)
方法2:优化标准库json的现有实现
如果必须依赖标准库json,可以用object_pairs_hook替代object_hook,减少一次字典构造的开销,优化现有逻辑:
import json def Load_JSON(s): def obj_pairs_hook(pairs): res = {} for k, v in pairs: res[k.encode('utf-8')] = v.encode('utf-8') if isinstance(v, unicode) else v return res return json.loads(s, object_pairs_hook=obj_pairs_hook)
虽然本质还是先解码再编码,但性能比原实现略优。
方法3:自定义字节流JSON解析器(进阶)
如果完全不想依赖现有JSON库的自动解码逻辑,可以手动实现字节流级别的JSON解析:
- 直接处理字节形式的输入,而非字符串。
- 手动识别JSON的语法分隔符(括号、逗号、引号等),提取键值对的字节片段。
- 仅处理必要的转义(如
\n、\"),保留原始UTF-8字节不转换为unicode。
这种方式复杂度较高,仅在无法使用第三方库时推荐。
内容的提问来源于stack exchange,提问作者personal_cloud

