Python编码问题
Python编码问题
编码问题是所有编程语言都不能回避的一个问题,编码解码总是剪不断理还乱,特别是在Python中,Python2版本和Python3版本在编码上还存在很大区别,所以更难理解。这篇博客讲梳理一下python的编码问题。
1、字符编码的历史
计算机只能处理数字,并且只能处理0,1这两个二进制数字,所以文本等必须转换为数字才能被计算机处理。计算机中8位(bit)作为一个字节(byte),所以一个字节最多只能表示0~255范围内256个不同字符,这已经能够表示全部的英文字符了,因此ASCII编码由此诞生
但是世界上语言有成千上万种,仅仅使用ASCII编码所有字符是明显不够的,比如我们的汉字就有几千种,因此我们国家制定了GB2312编码,用两个字节表示一个汉字,并且把ASCII码包含进去了。同理,韩国、日本等国家为了处理自己本国的语言,都发展了一套字节编码。编码标准因此越来越多,处理起来也越来越麻烦,因此有必要发展一套统一的囊括所有语言的通用字符集,这就是大名鼎鼎的Unicode,注意Unicode是一套字符集标准,只是规定了每一个字符如何用二进制代码表示,却没有规定这个二进制代码如何存储和传输。
举个例子,(1)英文字母“A”用ASCII编码的二进制表示是0100 0001,采用Unicode编码只需要在前面补0就可以,因此“A”用Unicode编码的二进制表示是00000000 0100 0001。(2)汉字“中”已经超出ASCII编码的范围,用Unicode编码的二进制表示是0100 1110 0010 1101。
现在采用Unicode编码不同字符的编码问题得到了解决,每一个字符都有唯一的二进制代码与之对应。但是也带来了一个另外的问题,如果我们的内容全是英文,Unicode编码的长度将比ASCII编码长一倍,因此需要多一倍的存储空间,网络传输时也要多一倍的带宽,这将是非常大的损耗。
为解决存储传输问题,许多Unicode编码的具体实现应运而生,UTF-8编码是Unicode编码的最常见实现,UTF-8编码是一种可变长编码,它采用1-4个字节表示一个字符,其中蕴含了出现频率高的字符对应的二进制表示尽可能短的思想。这样就解决了存储传输空间。
总结一下,在计算机内存中,所有的字符的采用Unicode编码,统一表示为两个字节,处理起来更加简单。在存储传输中,通常采用UTF-8编码,以节省空间。
所以就出现了编码和解码过程。
编码(encode):是将某个Unicode字符串按照一定的编码方式编码成字节序列。
解码(decode):是将一个字节序列按照一定的编码方式解码成Unicode字符串。
因此在读取文件时,我们只需要指明文件的编码格式,Java、Python等程序语言将自动采用这种编码格式将编码转化为Unicode。在保存文件时,我们也只要指明文件保存的格式,将Unicode编码的字符串保存为指定编码格式。
2、Python编码问题
Python2和Python3的编码存在很大的区别,具体来说
1、Python2
Python2系统内部默认的编码格式是ASCII编码,我们可以通过一下语句查看
import sys
sys.getdefaultencoding()
在Python2中存在两种字符串
s = " " # 类型是str,它是依操作系统而定的某种编码类型的字符串
s = u" " # 类型是unicode,Unicode编码类型的字符串
因为str类型字符串是采用操作系统编码格式编码的,Windows中文版默认编码GBK,Linux和Mac OS默认编码UTF-8。(.py文件中则是文件保存编码格式)所以在Python2内存中,需要先将其解码,然后再编码成其他格式。
从上图实验可以看到,在我们对字符串“s”进行编码时,首先会将“s”读入内存,也就是对“s”进行解码,因为Python2默认是ASCII编码,所以第一个语句相当于s.decode(“ascii”).encode(“utf-8”),与Windows控制台采用的GBK编码不同,所以会产生解码错误;同样第二句话采用UTF-8解码,与目标编码GBK不匹配而出错。只有我们指定用GBK解码时才会成功将字符串解码为Unicode编码,然后进行再编码。
当在字符串定义前面加上“u”时表示这是一个Unicode字符串,所以不需要经过解码处理。
2、Python3
Python3默认采用Unicode编码,因此在字符串处理中方便了许多。
s = " " # 类型str,Unicode编码类型字符串
Python3中字符串都是默认Unicode编码,因此在编码之前不需要先解码成Unicode编码格式。
3、其他
(1)# -*- coding: utf-8 -*-
由于Python2中,默认采用ASCII编码,因此在python源文件中如果存在中文等非ASCII编码时,Python解释器在编译解释源文件时就会抛出“SyntaxError: Non-ASCII character…”错误。通过在源文件头部声明如下语句
# -*- coding: utf-8 -*-
声明这句语句后,Python解释器将采用utf-8编码的格式读取文件。当然这也要求源文件的保存格式和文件头部声明的格式相同。
(2)Python默认编码格式修改
但是这依旧不能解决Python2中str字符串解码错误的问题,一种解决方法是在解码时明确指出字符串的编码格式
s.decode("gbk).encode("utf-8")
第二种解决方法是修改Python2默认的编码格式
import sys
reload(sys)
sys.setdefaultencoding("gbk")
s.encode("utf8")
这样就重新设置了Python2的默认编码格式,在没有指明解码格式时就将采用这个新的编码格式,也就是GBK。
(3)Python文件读写
Python文件读写是一块很大的内容,在这里不做详细介绍。总之,为了节省存储空间,文一般以UTF-8等编码格式存储于硬盘、数据库中,因此无论是Python2还是Python3将文件读取进内存时肯定存在解码的过程,一般为了避免解码错误,我们在打开文件时,通常会指明文件的编码格式。
参考文献
上一篇: python学习Day2——使用字符串
下一篇: Basic introduction