【python编码】 UnicodeDecodeError 分析和解决
现象
环境是linux,python2.7,执行以下代码:
import json a = '{"task_id": ["8061964"], "ch_reason": "\u589e\u52a0\u534f\u8bae\u7ba1\u7406\u6a21\u5757\uff0c\u7528\u6765\u7ba1\u7406\u5b58\u6b3e\u4ea7\u54c1\u7684\u6cd5\u5f8b\u534f\u8bae", "chg_type": ["0"]}' aa = json.loads(a) b = '变更原因' c = b + aa['ch_reason'] print c
出现如下异常:
原因
unicode指的是万国码,是一种“字码表”。而utf-8是这种字码表储存的编码方法。unicode不一定要由utf-8这种方式编成bytecode储存,也可以使用utf-16,utf-7等其他方式。目前大多都以utf-8的方式来变成bytecode。
其中,python里的字符串类型分为byte string 和 unicode string两种。
如果在python文件中指定编码方式为utf-8(#coding=utf-8),那么所有带中文的字符串都会被认为是utf-8编码的byte string(例如:mystr="你好"),但是在函数中所产生的字符串则被认为是unicode string。
问题就出在这边,unicode string 和 byte string 是不可以混合使用的,一旦混合使用了,就会产生如上的错误。
解决方案
方案一:修改全局默认编码
import sys reload(sys) sys.setdefaultencoding('utf-8')
缺点:一旦加载就修改了全局的编码,有风险。优点:简单粗暴。
方案二:手动将unicode对象的编码改为utf-8
将unicode对象的编码改为utf-8,即可和python 中的byte string 之间互相操作了。
def unicode_convert(input): if isinstance(input, dict): return {unicode_convert(key): unicode_convert(value) for key, value in input.iteritems()} elif isinstance(input, list): return [unicode_convert(element) for element in input] elif isinstance(input, unicode): return input.encode('utf-8') else: return input def test(): unicode_obj = u'我是unicode' str_obj = unicode_convert(unicode_obj) assert isinstance(str_obj, str)
如果要在json反序列化中使用,还可以使用以下方式:
json.loads(unicode_obj, object_hook=unicode_convert)
优点:按需转换。
缺点:可能有遗漏。
总结
方案二更加合适。