谈谈Python2里的编码问题

Python2中的编码问题是所有用python做过数据处理,文本导入导出无法避免又头疼的问题,最近又碰到要处理中文的问题,总结一下解决过程中的心得。

编码问题是怎么出现的

当代码或者读入写出的文本中出现非英文字符时,大家一定不陌生这个exception:

要解决问题之前,要了解为什么会出现问题。

这个error意思是,ascii字符集无法将字节0xe4转译到128字符当中。那么ascii字符集是什么,它又要做转译?

ascii的全称是American Standard Code for Information Interchange,即美国信息交换标准代码。我们都知道计算机的世界里只有0和1,所有数据都会变为这两个数字交给计算机处理,那么人类的指令是怎么转化为0和1的呢?最早的ascii便是由此而生,ascii把英文当中的26个字母大小写,常用标点符号和一些不可见字符一共128个字符一一编号,比如a是第97个字符,当我在命令行或者ide里面输入a,根据ascii,计算机就能理解这是1100001(97的二进制值),而当我们去读取数据,遇到97时,通过ascii字符集查询到了“a”,那么计算机就会给我们显示出a。所以像ascii字符集是人类和计算机交流的翻译字典。

而python2被发明时,基本上只有ascii这个通用的字符集被使用,于是py2就把ascii当作默认的字符集,直到计算机的普及,出现了ascii无法理解的字符,比如中文,韩文,日文,俄文…… 于是就出现了这个UnicodeDecodeError。

Unicode和UTF-8

为了解决,非英文字符的表达,一种可以包含所有符号的编码变得势在必行,Unicode即是为此诞生。ascii只有128种字符,二进制7位即可表示,在前面补了一位0,一个字节(8bits)可以存储。而加入其他语言符号后,一个字节显然不够用了,于是Unicode使用三或四个字节为几万种出现在各国语言的字符编号。

但是Unicode有个问题,它只规定了每个字符的二进制代码,并没有规定每个字符应该怎么存储,比如“中”的unicode值是4e2d,二进制表示是100111000101101,有15个bit只少需要2个字节存储,那计算机怎么区分这是一个unicode字符还是两个ascii字符呢?

为了解决统一的编码表示方式,互联网统一了一种编码就是utf-8。可以把它理解为ascii的一种拓展,用更多的二进制位数去表示unicode中的符号。在整个编码规则的发展中,还衍生了ISO, GBK, GB2312等,他们都是unicode的实现形式。换而言之,unicode是通用的字符编号定义,但每个字符的二进制值在不同的编码方式中的表现是不一样的,举个例子,unicode值为4e2d,它在utf-8的规则中可能值为1,而在gbk的规则中可能为2,在ascii中可能就找不到对应的值。

decode()/encode()

python2处理字符串是按照unicode值来操作的,例如对比两个字符串是否相等,就是比较两个字符串的unicode值是否相等。所以如果要在代码中hard code某些非英文字符,之后要用作字符串处理,最好在前面加u:

这样处理就是把"中文"的unicode值存在s中,无论要和哪种编码方式比对都先转成unicode来比较。

decode()是把其他编码类型的字符串转成unicode,反过来要打印或者输出unicode,就需要按指定的编码方式encode():

总的来说,编码问题在编程时会在以下三种情形下出现:

代码层面,即在代码中写了非英文字符意外的字符,通常会报这个错误:

所以推荐在文件第一行定义:

当执行python文件时,编译器读到这一行就知道,当前这个文件存储的代码是以utf-8的形式表达的,才能正确的翻译成机器能理解的命令。

执行层面,即runtime,我们做数据处理的时候,常常会做一些字符串处理和类型转换,强制使用str()。str()是python built-in函数,是把传入的object转为可显示的字符。一般来说,默认的编码方式是ascii,如果要转的是中文,那么就会出现文首那个错误了。例如强制转一个已经是unicode的变量:

输入输出,当我们把python里面的字符串打印到console或者从文件中读入读出字符串时,如果不知道读入的文字是什么编码的,用默认的编码方式就有可能报错或者显示乱码。所以在输出时,先将字符串decode成unicode,在encode成指定的编码形式。

另外提醒一点的是,如果输出是utf-8格式,导出到文件,或者http response里有中文,需要提前告知文件或response接下来的内容都是utf-8的编码:

如此一来,其他应用打开这个文件时,就知道这个文件是utf-8的编码,html文件也有类似的定义。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180301G1H6UC00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券