字符编码
常用字符编码有ASCII
,GB2312
,Unicode
,UTF-8
等,为什么需要这么多不同的编码,又是怎么来的呢?
计算机能够识别的只有二进制的0和1,要处理字母等类型只能转换为类似01010001
的二进制数字才能处理;人要能够正常阅读,也需要计算机将二进制数转换为对应的字母。那么如何转换,转换的规则和标准又是什么?这就是我们常见的编码所规定的。
ASCII
计算机是美国人发明的,因此最早只有英语中的127个字符(包括大小写字母、数字、特殊符号等)被编码到计算机里,这个编码表就是ASCII
编码。根据前面一个字节(8比特)最多可以表示256
个字符,那么对于英文中的100多个字符使用一个字节中的前7位就可以表示。
GBK
英文是可以被计算机识别了,那么中文怎么破?为了解决汉字问题,中国国家标准总局提出了GB2312
编码,收录了6763个汉字,后来又在此基础上创建了GBK
编码,收录了27484汉字,同时收录了包括藏文、蒙文等在内的主要少数名族文字。
Unicode
中文使用GBK
编码,那么对于其他国家的文字如何处理,各个国家都有建立了自己的标准。为了统一标准,统一联盟国际组织提出了Unicode
编码,该编码将所有语言统一到一套编码。
Unicode标准也在不断发展,最常见的是两个字节表示一个字符(生僻字符可能需要4个字节)。ASCII
和Unicode
主要区别:ASCII编码使用1个字节,Unicode编码通常是2个字节。
字母
A
用ASCII编码是十进制的65
,二进制的01000001
;
字符0
用ASCII编码是十进制的48
,二进制的00110000
;
汉字中
已经超出ASCII编码范围,用Unicode编码是十进制的20013
,二进制的01001110 00101101
;
ASCII编码的A
用Unicode编码,只要在前面补0就可以,A
的Unicode编码是00000000 01000001
。
从上面可以看出,假如对英文使用Unicode编码要比ASCII编码多一倍的存储空间,在存储和传输上不方便。
所以本着节约的精神,又出现了把Unicode编码转换为可变长编码的UTF-8
编码。UTF-8编码把一个Unicode字符根据不同数字大小编码成1-6个字节,常用的英文字母编码成1个字节,汉字通常是3个字节。当传输的文本中包含大量的英文字符时,用UTF-8编码可以节省空间。
上面内容总结一下就是
- 为处理英文字符,出现了
ASCII
码。 - 为处理中文字符,出现了
GB2312
和GBK
。 - 为统一处理不同国家不同语言,出现了
Unicode
编码。 - 为提高Unicode传输和存储的性能,出现了
UTF-8
,它是Unicode的一种实现方式。python2的字符编码
python2中默认的字符编码是ASCII
码,也就是说在处理数据时,若没有指定它的编码类型,默认将会当做ASCII码来处理。当编写的python文件中包含有中文字符时就会报错。1
2
3#!/usr/bin/env python
s = "是否乱码"
print(s)
执行结果
根据上述结果可以看到出错原因是python将整个脚本当做ASCII码处理,但是出现的中文是否乱码
ASCII码无法处理。处理方式很简单,在头部添加一行编码声明。1
2
3
4#!/usr/bin/env python
# -*- coding: UTF-8 -*-
s = "是否乱码"
print(s)
执行结果
pycharm执行
windows命令行执行
声明编码方式之后发现在pycahrm执行输出正确信息,但是在windows命令行输出乱码。
windows命令行默认使用的是GBK
编码,但是在python脚本中使用的是UTF-8
,两边不一致导致出现乱码,只要修改两者一致即可。1
2
3
4#!/usr/bin/env python
# -*- coding: GBK -*-
s = "是否乱码"
print(s)
执行结果
此时可以看到在命令行执行结果显示正确,但是相应的在pycharm执行就会出现乱码的情况。也进一步说明导致乱码就是编码格式不一致。也就是说,当需要操作系统正确输出一个字符时,除了要知道该字符的字符编码,还需要知道自己使用系统的字符编码,两者一致时就不会出现所谓乱码
。
decode()和encode()
decode()方法将其他编码字符转换成Unicode编码字符。
encode()方法将Unicode编码字符转换成其他编码字符。
上述命令在pycharm自带的终端执行,其默认字符编码为UTF-8
。
直接输入s
出现的'\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81'
为对应的UTF-8字符串。
使用decode()方法将s转换为unicode编码,此时输入unicode_s
出现的u'\u662f\u5426\u4e71\u7801'
为unicode字符串。
使用encode()方法将unicode_s转换为GB2312编码,此时输入gb2312_s
出现的'\xca\xc7\xb7\xf1\xc2\xd2\xc2\xeb'
为gb2312字符串。由于终端为UTF-8编码,所以使用print gb2312_s
会出现乱码情况。
在windows终端可以正常输出gb2312编码的字符串。
总结
- python2中可以直接查看unicode字符串。
- python2中对于字符编码的转换通过unicode作为中间人进行转换。
- decode()方法与在字符串前加u的方法实现的效果相同。
python2中的列表
1
2
3
4
5"哈哈","ABC"] list1 = [
list1
['\xb9\xfe\xb9\xfe', 'ABC']
print list1[0]
哈哈
当一个中文的字符出现在列表(或元组或字典)中,它不会被显示为中文而是显示为字符串。但是当该字符窜从列表中取出再使用print时就可以正常显示为中文。
字符串是所有字符在python2中的本质形态,该字符串是计算机可以理解的,不是通常所说的乱码。在python3中就不存在这种问题了。
python3的字符编码
在python3中默认编码方式为UTF-8
,所以coding声明可以不用写,但为了兼容python2建议添加。
python3中字符串类型是str
,在内存中以Unicode表示,一个字符对应若干个字节。当需要传输或者保存到硬盘时,就需要把str
变为以字节为单位的bytes
。
以Unicode表示的str
通过encode()方法可以编码为指定的bytes
。1
2
3
4"ABC".encode('ASCII')
b'ABC'
"是否乱码".encode('UTF-8')
b'\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81'
bytes
类型的数据用带b
前缀的单引号或者双引号表示。- 在
bytes
中无法显示为ASCII字符的字节,用\x##
表示。
相反,要将bytes
变为str
,就需要使用decode()
方法。1
2
3
4b'ABC'.decode('ASCII')
'ABC'
b'\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81'.decode('UTF-8')
'是否乱码'
上面说到的编码问题主要是python2中,请注意区分版本。
即使在python3中,涉及到str
和bytes
转换时,非特殊情况一定要使用UTF-8
编码。