编码问题总结
总结下编码问题的相关概念。
字符集和编码的区别
字符集(Character Set)是字符的集合,即为每一个字符分配一个唯一的ID(码点,Code Point)。
编码(Encoding)是把码点转化为字节序列的规则。因为在实际存储中不一定是直接存储字符的码点(比如为了节约空间),所以需要一种转换规则,这种规则就是编码。
ASCII,GB2312,GBK都是字符集,同时它们也代表了对应的编码方式(不严格区分)。
Unicode是一种字符集,但它的编码方式有多种,如utf-8和utf-16。
各种字符集和编码
ASCII:储存所有英文字符和部分符号,由0~127表示,每个字符为1字节。
GB2312:是
ASCII
码的中文扩展,小于127的字节与原来相同,而用两个大于127的字节来表示中文,加入了大约7000个汉字。同时把ASCII
码中的原有字符重新编GBK:是对
gb2312
的扩展,规定只要高字节大于127则就表示这是一个汉字的开始,从而又增加了20000多个汉字。后来又加入几千个少数民族的字,扩展为GB18030
。ANSI:不同国家制定了不同标准,包括美国的
ASCII
,中国的GBK
,日本的Shift_JIS
,韩国的Euc-kr
等。这些不同国家的编码标准合称为ANSI
编码。不同的ANSI
编码之间互不兼容,对于简体中文系统,ANSI
编码就等同于GBK
编码。Unicode:是一套字符集,包括了世界上所有的文字和符号。总空间为17个平面(0x0000~0x10ffff),最常用的0号平面(MBP)包含65535个码点,以2个字节表示。
UTF-8:是
unicode
的一种编码方式,将一个码位编码成1~4字节。
对于单字节的字符,字节的第一位设为0,与ASCII
码相同;而对于n个字节的字符(n>1),第一个字节的前n位设为1,第n+1位设为0,后面字节的前两位都设为10,其余空位由低到高地填充该字符unicode码,高位用0补足。
UTF-8
编码将英文字符编码为1字节,将汉字一般编码为3字节,相比直接存储unicode
码点节约了空间。U+ 0000 ~ U+ 007F: 0XXXXXXX U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
- Windows默认使用GBK编码,而Linux系统默认使用UTF-8编码,不同系统间文件传输时需进行转码。
Python编码问题
在Python内部,字符串(str)以
unicode
形式存在,即每一个字符存在对应的唯一的编号,ord(str)
可以获取该编号(即为码点),chr(codepoint)
可以获取编号对应的字符。>>> ord('a') 97 >>> ord('中') 20013 >>> chr(20013) '中' >>> '\u4e2d' '中'
编码和解码
Python的字符串(str)在内存中以Unicode
形式存在,如果需要在网络中传输或是存储在硬盘中,则要通过encode()
编码成字节流(bytes)。同样,从网络或磁盘中读取到的字节流可以通过decode()
解码成字符串。>>> 'ABC'.encode('ascii') b'ABC' >>> '中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87' >>> '中文'.encode('gb2312') b'\xd6\xd0\xce\xc4' >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') '中文'
- 文件IO的编码问题
Python可以使用open()
打开文件,接收参数依次为文件路径,打开方式(r/w),编码方式(encoding)。
如果是读取文件,则encoding
参数指定的是将文件内容解码(decode)为字符串str(unicode)所用的编码方式,此时encoding
应与文件编码保持一致。
如果是写入文件,则encoding
指定的是将字符串(unicode)编码(encode)并存储于文件所用的编码方式。
Python中打开文件,如果不指定encoding
参数,则默认使用cp936
,也就是我们熟悉的GBK
编码。