python---字符编码问题

问题

最近在用python 2.7写代码的时候,遇到一个老生常谈的小坑----- ** 字符编码 **

import MySQLdb
conn = MySQLdb.connect(host=..., user=..., passwd=..., db=..., charset='utf8', port=...)  //此处已设置charset为utf8

从数据库获取到的数据是:value = '\u6295\u8d44。。。。。' ** 注意:前面没有u **
然后在django后端views.py中,

from django.http import JsonResponse

用JsonResponse(value)返回数据,前端进行渲染,结果在页面上不显示返回结果。

排查过程

  • 打开chrome的console调试,发现报错500--Internal Server Error。。。
  • 查看log发现出现两种报错:'utf8' codec can't decode bytes in position 3-4: invalid continuation byte 和 'ascii' codec can't decode byte 0xe4 in position 0
  • views.py的开头,已经指定了utf-8显示:
# -*- encoding: utf-8 -*-
importsyswufazhengquejiexi
reload(sys)
sys.setdefaultencoding('utf-8')

调试(工具为ipython)

python---字符编码问题_第1张图片

查看变量value的类型,可见value并不是unicode类型,而是str类型

分析

首先我们看下在python中,unicode 和 utf-8/gb2312/ascii 的区别 (参照百度百科)

  • unicode :在python中是一个类,函数unicode(str,"utf8"),将utf8编码(或其他编码)的字符串str转换为unicode类的对象。它表示一个变量的类型,可以用isinstance(value, unicode)来查看value变量是否为unicode格式的字符。
  • ascii :是一种字符集,包括大小写的英文字母、数字、控制字符等,翻译为美国信息互换标准代码,是美国国家标准学会(ANSI)制定的英文编码。
  • gb2312:国标码,是对 ASCII 的中文扩展
  • utf-8:是一种针对unicode的可变长度字符编码,它是在互联网上使用最广的一种unicode的实现方式,是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了
  • gb2312和utf-8都是按照unicode规定的方式,用不同的编码排列方式,将字符与二进制的01进行对应的表。

然后我们研究下python中的encode和decode函数:

unicode_1 = u'中文'
str_1 = unicode_1.encode('gb2312')

将unicode对象unicode_1用gb2312编码,得到str类型变量str_1,结果见图:


python---字符编码问题_第2张图片
unicode_2 = str_1.decode('gb2312')

用gb2312编码对字符串str_gb进行解码,得到unicode类型对象,结果见图:

python---字符编码问题_第3张图片

decode()和encode()关系如图:


python---字符编码问题_第4张图片

解决办法

现在回到我们的问题中,查看了一下mysql数据库,发现里面存储的数据确实是utf-8格式,因此用网上搜到的方法

value = value.decode('gb2312').encode('utf-8')

来修改代码,前端仍然不显示。这里是因为数据库里存储的并非gb2312格式的数据,所以decode是没用的。
再查,发现产生 ‘XXX' codec can't decode bytes in position XX 这种错误信息的真正原因,竟然是decode过程中遇到了非法字符,因此无法正确解码(参照:blog.csdn.net/cnmilan/article/details/9264643)。
而在做decode时,加上ignore参数,则会忽略非法字符:

value = value.decode('utf-8', 'ignore').encode('utf-8')

至此,问题得到解决。

总结

一定要真正理解unicode和utf-8的区别,还有要梳理清楚decode()和encode()的关系,排查出问题的真正原因,而不是随便在网上搜索模糊的答案,一来未必能真正解决问题,二来永远不会进步!

你可能感兴趣的:(python---字符编码问题)