python笔记6--编码
总结:
1.字符串类型包括两种:str和unicode。严格意义上来说str是字节串,由unicode经过编码后的字节组成;unicode才是真正意义上的字符串,由字符组成。
2.str -> decode(解码) -> unicode
unicode -> encode(编码) -> str
- 编码(encode):将Unicode字符串(中的代码点)转换特定字符编码对应的字节串的过程和规则
- 解码(decode):将特定字符编码的字节串转换为对应的Unicode字符串(中的代码点)的过程和规则
3.2系列python的默认编解码格式是ASCII。字符转换需要从unicode格式转换,非unicode格式字符转换时需要先解码为unicode格式,如果没有配置解码格式,系统会使用默认的解码格式进行解码。
例如一个中文的str配置utf-8进行编码,系统会使用默认的ASCII进行解码,由于ASCII无法解码中文,系统则会报错。
相关概念
1.字符和字节
一个字符不等价于一个字节,字符是人类能够识别的符号,而这些符号要保存到计算的存储中就需要用计算机能够识别的字节来表示。一个字符往往有多种表示方法,不同的表示方法会使用不同的字节数。这里所说的不同的表示方法就是指字符编码,比如字母A-Z都可以用ASCII码表示(占用一个字节),也可以用UNICODE表示(占两个字节),还可以用UTF-8表示(占用一个字节)。字符编码的作用就是将人类可识别的字符转换为机器可识别的字节码,以及反向过程。
UNICDOE才是真正的字符串,而用ASCII、UTF-8、GBK等字符编码表示的是字节串。关于这点,我们可以在Python的官方文档中经常可以看到这样的描述"Unicode string" , " translating a Unicode string into a sequence of bytes"
我们写代码是写在文件中的,而字符是以字节形式保存在文件中的,因此当我们在文件中定义个字符串时被当做字节串也是可以理解的。但是,我们需要的是字符串,而不是字节串。一个优秀的编程语言,应该严格区分两者的关系并提供巧妙的完美的支持。JAVA语言就很好,以至于了解Python和PHP之前我从来没有考虑过这些不应该由程序员来处理的问题。遗憾的是,很多编程语言试图混淆“字符串”和“字节串”,他们把字节串当做字符串来使用,PHP和Python2都属于这种编程语言。最能说明这个问题的操作就是取一个包含中文字符的字符串的长度:
- 对字符串取长度,结果应该是所有字符串的个数,无论中文还是英文
- 对字符串对应的字节串取长度,就跟编码(encode)过程使用的字符编码有关了(比如:UTF-8编码,一个中文字符需要用3个字节来表示;GBK编码,一个中文字符需要2个字节来表示)
注意:Windows的cmd终端字符编码默认为GBK,因此在cmd输入的中文字符需要用两个字节表示
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> # Python2 >>> a = 'Hello,中国' # 字节串,长度为字节个数 = len('Hello,')+len('中国') = 6+2*2 = 10 >>> b = u 'Hello,中国' # 字符串,长度为字符个数 = len('Hello,')+len('中国') = 6+2 = 8 >>> c = unicode (a, 'gbk' ) # 其实b的定义方式是c定义方式的简写,都是将一个GBK编码的字节串解码(decode)为一个Uniocde字符串 >>> >>> print ( type (a), len (a)) (< type 'str' >, 10 ) >>> print ( type (b), len (b)) (< type 'unicode' >, 8 ) >>> print ( type (c), len (c)) (< type 'unicode' >, 8 ) |
2.python源代码执行过程
磁盘上的文件都是以二进制格式存放的,其中文本文件都是以某种特定编码的字节形式存放的。对于程序源代码文件的字符编码是由编辑器指定的,比如我们使用Pycharm来编写Python程序时会指定工程编码和文件编码为UTF-8,那么Python代码被保存到磁盘时就会被转换为UTF-8编码对应的字节(encode过程)后写入磁盘。当执行Python代码文件中的代码时,Python解释器在读取Python代码文件中的字节串之后,需要将其转换为UNICODE字符串(decode过程)之后才执行后续操作。
上面已经解释过,这个转换过程(decode,解码)需要我们指定文件中保存的字节使用的字符编码是什么,才能知道这些字节在UNICODE这张万国码和统一码中找到其对应的代码点是什么。这里指定字符编码的方式大家都很熟悉,如下所示:
1
|
# -*- coding:utf-8 -*- |
3.字符编解码转换
UNICODE字符串可以与任意字符编码的字节进行相互转换,如图:
那么大家很容易想到一个问题,就是不同的字符编码的字节可以通过Unicode相互转换吗?答案是肯定的。
Python2中的字符串进行字符编码转换过程是:
字节串-->decode('原来的字符编码')-->Unicode字符串-->encode('新的字符编码')-->字节串
Python3中定义的字符串默认就是unicode,因此不需要先解码,可以直接编码成新的字符编码:
字符串-->encode('新的字符编码')-->字节串
最后需要说明的是,Unicode不是有道词典,也不是google翻译器,它并不能把一个中文翻译成一个英文。正确的字符编码的转换过程只是把同一个字符的字节表现形式改变了,而字符本身的符号是不应该发生变化的,因此并不是所有的字符编码之间的转换都是有意义的。怎么理解这句话呢?比如GBK编码的“中国”转成UTF-8字符编码后,仅仅是由4个字节变成了6个字节来表示,但其字符表现形式还应该是“中国”,而不应该变成“你好”或者“China”。