Python中的编码
本文将会介绍Python2和Python3中的字符编码。
实验环境需要Python2和Python3。install Python2 & Python3
首先我们要理清楚一些概念。
字节与字符
计算机的世界是由用0和1组成,这叫比特bit。当计算机存储一个文件时,文件是由一串01的字节序列构成,字节Byte等于8个bit。字符是一个符号,汉字、日语、数字、标点等。字节"01100001"
方便存储和传输、字符a
方便阅读。
编码与解码
将字符转换为字节的过程叫做编码encode;反过来,将字节转换成字符的过程叫做解码。
这里有个问题,我的字符"a"
为什么编码成了0110001
,而不是01010101
这种动词打次的节奏?这就有了字符集的概念,它为包含的每一个字符指定了一个唯一数字(编码)。在这里a
的编码是97
写成二进制就是0110001
。下面介绍两种字符集ASCII和Unicode。
ASCII
ASCII(American Standard Code for Information Interchange)最开始只定义了128个字符编码。字符与ASCII码的对应关系可以查看ascii-code
当非英语国家人开始使用电脑,这个字符集所包含的字符就不够用了。于是各个国家有了自己的字符集,中文的字符集就经历了从GB2312到GBK再到GB18030的过程。但是,各个国家都有自己的一套标准,这样子是没有办法交流的,所以就有的Unicode。
Unicode
为了统一地球上所有字母、符号,ISO(国际标准化组织)制定了Universal Multiple-Octet Coded Character Set,简称UCS,俗称Unicode。它给世界范围内每个character指定了一个唯一数字。字符与Unicode码表unicode-chart
Unicode有两种格式:UCS-2和UCS-4,分别表示使用2个字节和4个字节编码。如在python2中字
的UCS编码是5b57
就是两个字节[1]。不过两个字节最多表示65535个字符,而4个字节可以表示到100多万个字符。
有了统一Unicode码后,这里就涉及到了如何把一个Unicode码转换成Bytes。
UTF-8
UTF-8 (Unicode Transformation Format)就是最主要的一种将Unicode码U+597D
转换成字节\xe5\xa5\xbd
的编码方式[3]。它是一套以8位为一个编码单位的可变长编码,会将一个unicode码编码为1到4个字节。
使用UTF-8编码后,原来的ASCII字符集中的字符还是使用一个字节表示,这是对与ASCII很好的兼容性。
Unicode符号范围(十六进制) | UTF-8编码方式(二进制) |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
以汉字好
为例unicode码为597D
,对应的区间是0000 0800--0000 FFFF
从上表可对应到3个字节的UTF-8编码,通过如下示例中转换最终得到16进制utf-8码\xe5\xa5\xbd
。
中文 好
unicode 0101 100101 111101 # U+597D
编码规则 1110xxxx 10xxxxxx 10xxxxxx
--------------------------
utf-8 11100101 10100101 10111101
--------------------------
16进制utf-8 e 5 a 5 b d
Python2
理清楚了上面的概念后,来说说在Python中的unicode、utf-8、编码。
先从Python2中说起,Python2有如下两个特点:
- Python2中使用ASCII作为默认编码方式。
- Python2中字符串可以使用unicode和str两种类型表示。
对于好
这个字,用str表示时,它对应的就是utf-8编码的(Bytes)'\xe5\xa5\xbd'
,而用unicode码就是u'\u597d'
[4]。从Byte到unicode是解码,从unicode到Byte时encode。
In [2]: type('好'), type(u'好'), '好', '好'.decode('utf8'), u'好'.encode('utf8')
Out[2]: (str, unicode, '\xe5\xa5\xbd', u'\u597d', '\xe5\xa5\xbd')
对于unicode和str的长度。每个unicode码都是长度为1,str的长度则是表示str的byte个数。如汉字你
和好
使用UTF8编码后都占3个字节。
In [3]: len(u'你好'), len(u'你好'.encode('utf8'))
Out[3]: (2, 6)
In [4]: len(u'hi \u2119'), len('hi')
Out[4]: (4, 2)
Python2中使用ASCII作为默认编码。但是ASCII编码的字符范围很小,一不小心遇到中文就很容易出错。
In [5]: sys.getdefaultencoding()
Out[5]: 'ascii'
下面举几个容易出现问题的情况:
在编码和解码时字符集不匹配,超出了编码范围。
>>> my_unicode = u'你好' >>> my_unicode.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
str和unicode混着使用时,implicityly decode[5]。实际是使用
sys.getdefaultencoding()
来decode了str后和unicode做字符串连接。>> u'你好' + 'world' u'\u4f60\u597dworld' >>> u'你好' + '世界' # '世界'.decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
在文件中有非ascii字符时,文件开头缺少code encoding信息。
# -*- coding: utf8 -*- # 如果缺少code encoding信息,python t.py时也会出现编码问题。 print '你好'
Python3
Python3中,我还没有用起来。
参考资料:
- python3 unicode howto
- python之禅中和python编码相关的文章
- Youtube - Pragmatic Unicode, or, How do I stop the pain? 半个小时值得拥有
- PEP 263 – Defining Python Source Code Encodings
注[1]:想知道python使用的unicode是两个字节还是四个字节。
In [28]: import sys; sys.maxunicode # python3是四个字节
Out[28]: 1114111
In [56]: import sys; sys.maxunicode # python2是两个字节
Out[56]: 65535
注[2]:python3如何获得unicode码。
注[3]:常见的有UTF8和UTF16,分别表示以8位和16位为单位对unicode进行编码。
注[4]:需要补充一点的是,str类型的字符其具体的编码格式是UTF-8还是GBK,还是其他格式,根据操作系统相关。这点我也需要再理清楚一下。
注[5]:str和unicode混着使用,除了+
外,其他很多情况也都会implicityly decode和encode。
"Title %s" % my_unicode # 'Title' -> decode
u'Title %s' % my_utf8 # my_utf8 -> decode
print my_unicode # 我的环境竟然没有出错,不是应该ascii encode错了。