在上一小节的学习中,我们解决了python解析器输出汉字乱码的问题。但是一些关于编码的概念并没有解析清楚。这一小节,将继续学习字符编码的知识。

 

先提出以下问题:

1.什么是字符编码?

2.什么是ACSII编码?

3.什么是Unicode编码?

4.什么是UTF-8编码?

5.什么是cp950编码?

 

在开始之前我们需要先理解什么是编码?

在一些电影情节中,我们经常会看到某个活动于“地下的英雄们”在做一些不法活动时,通常用手电的“明,灭”或者“在空中画个大圈圈”来向对方传递某种不为人知的信息。在这里手电的明灭就是一种信息编码,传递了双方事先约定好的信息,比如“亮-灭--亮-灭”表示危险取消交易,“画个大圈圈”表示OK,安全可以交易。

python编码字节串还是原始字符 python中的字符编码_python编码字节串还是原始字符

图1

从图1我们可以知道,把信息以事先约定好的规则(编码原则)转化为另一种方式(方便使用工具传播比如手电的光信号),这就是对信息编码。

A把信息“有危险取消交易”的信息转换为手电信号“亮-灭-亮-灭”这个过程是编码(encode)。

B收到信号“亮-灭-亮-灭”根据事先约定的信息把这个信号翻译为“有危险取消交易”这个过程是解码(decode)。

 

再更进一步学习字符编码前,先学习下字符在内存中的存储。在X86CPU计算机实现中规定(X86表示CPU指令集,详细信息参考维基百科条目):

8位二进制代码称为一个字节(byte)。

双字节16位二进制代码表示为一个字(word)。

双字32位二进制代码表示为双倍字(dword)。

4个字64位二进制代码表示为四倍字(qword)。

字节是计算存储的最小单位,也是内存地址编码的最小单位。操作系统为内存单元也就是为每个字节指定一个值,这就是我们在上一节中使用id()可以输出的内容。

而在数据存储上又有“大小端之分”。

python编码字节串还是原始字符 python中的字符编码_python编码字节串还是原始字符_02

0A是最高有效位,存储在内存的低地址位,这称为大端序。

python编码字节串还是原始字符 python中的字符编码_操作系统_03

0A是最高有效位,存储在内存的高地址,这称为小端序。

(上图来源维基百科,参考文末链接)

 

我们都知道在计算机内部CPU执行的指令都是01二进制代码,如果计算机只能输入和输出01代码,阅读起来太过痛苦也不便于计算机的推广使用,于是ASCII编码就被开发出来,用01序列来表示我们人类可以识别的自然语言。

ASCII(American Standard Code for Information Interchange 美国信息交换标准代码)采用了一个字节来编码英文世界的信息。

具体来说只使用了低7位(第八位也就是最高位默认为0,第一位又称为最低位),127个字符就满足了英文编码的需要。

python编码字节串还是原始字符 python中的字符编码_python_04

图2

python编码字节串还是原始字符 python中的字符编码_操作系统_05

图3来源于维基百科

0~32和第127个位置,总共33个控制字符,控制字符不会在终端(显示器)上显示主要用来实现特殊的目的,比如换行和退格。

在编程中经常使用的是第10个字符换行和第十三个回车键(enter键)。这个一部分符号历史可以追溯那种古老的机械打印机。

余下94个字符都是可以显示字符,其中48~57表示数字0~9,第65~90表示大写字母‘A’~‘Z’,第97~122表示小写字母'a'~'z'

(更容易阅读的ASCII表见文末)

 

随着计算机在全世界范围内广泛使用,ASCII不能满足更广范围的编码需求,比如汉字的编码,目前的GB2312汉字编码是使用两个字节来实现汉字的编码的,

理论上可以实现256*256 = 65536个汉字。但是目前统计说有10万汉字,要想实现这么多的汉字编码就需要使用Unicode编码,当然在存储上会占用更多的字节。

Unicode用来解决全世界范围内的字符编码问题。Unicode像ASCII一样只是定义了二进制字符序列与字符的对照关系。

 

我们测试下一个汉字采用ASCII编码和Unicode会有什么区别。

在windows记事本,中输入汉字“万”,分别另存为,ANSI编码,Unicode编码,Unicode bigendian编码和UTF-8编码。

python编码字节串还是原始字符 python中的字符编码_操作系统_06

然后是用UltaEdit的切换16进制模式查看。



汉字 “万” 
ANSI编码:C9 45
Unicdoe编码: FF FE 07 4E
Unicode Bigendian:FE FF 4E 07
UTF-8: EF BB BF E4 B8 87



(这例子学习自阮一峰的blog,阮大师举例为“严”,这里采用“万”字,是为了自己学习,链接见文末)

“万”的Unicode的编码可以在“Unicode与汉字对照表”查到是“4E07”说明对照表中编码是Big endian的。

记事本中的Unicode是采用little endian方式存储的,双字节的UCS2实现。



Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。
如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。(摘自阮一峰blog)



UTF-8以EF,BB,BF开头表示文档的编码格式,实际上“万”字的UTF-8表示为:E4 B8 87

通过上面的例子我们可以看到UTF-8与Unicode编码不同,UTF-8是Unicode的一种实现方式。UTF-8编码采用了变长的字节存储比Unicode节省空间,且兼容ASCII字符,是目前网络最通用的一种编码方式。

 

在我们最后的一个问题中的cp950是“操作系统实现的字符集”,这个在windows中表示繁体字符集。

 

在python2.7中已经支持了Unicode字符集,在不同的字符集之间切换需要借助utf-8编码为中间码做转换,然后再转换为目标字符集。



print(msg.decode("utf-8").encode("950"))



 

二进制

十六进制

十进制

缩写

Unicode

脱出字符

名称/意义

表示法

表示法

0000 0000

0

0

NUL


^@

空字符(Null)

0000 0001

1

1

SOH


^A

标题开始

0000 0010

2

2

STX


^B

本文开始

0000 0011

3

3

ETX


^C

本文结束

0000 0100

4

4

EOT


^D

传输结束

0000 0101

5

5

ENQ


^E

请求

0000 0110

6

6

ACK


^F

确认回应

0000 0111

7

7

BEL


^G

响铃

0000 1000

8

8

BS


^H

退格

0000 1001

9

9

HT


^I

水平定位符号

0000 1010

0A

10

LF


^J

换行键

0000 1011

0B

11

VT


^K

垂直定位符号

0000 1100

0C

12

FF


^L

换页键

0000 1101

0D

13

CR


^M

Enter键

0000 1110

0E

14

SO


^N

取消变换(Shift out)

0000 1111

0F

15

SI


^O

启用变换(Shift in)

0001 0000

10

16

DLE


^P

跳出数据通讯

0001 0001

11

17

DC1


^Q

设备控制一(XON 激活软件速度控制)

0001 0010

12

18

DC2


^R

设备控制二

0001 0011

13

19

DC3


^S

设备控制三(XOFF 停用软件速度控制)

0001 0100

14

20

DC4


^T

设备控制四

0001 0101

15

21

NAK


^U

确认失败回应

0001 0110

16

22

SYN


^V

同步用暂停

0001 0111

17

23

ETB


^W

区块传输结束

0001 1000

18

24

CAN


^X

取消

0001 1001

19

25

EM


^Y

连接介质中断

0001 1010

1A

26

SUB


^Z

替换

0001 1011

1B

27

ESC


^[

退出键

0001 1100

1C

28

FS


^\

文件分区符

0001 1101

1D

29

GS


^]

组群分隔符

0001 1110

1E

30

RS


^^

记录分隔符

0001 1111

1F

31

US


^_

单元分隔符


0111 1111

7F

127

DEL


^?

删除

 

二进制

十六进制

十进制

图形

0010 0000

20

32

(空格,␠)

0010 0001

21

33

!

0010 0010

22

34

"

0010 0011

23

35

#

0010 0100

24

36

$

0010 0101

25

37

 %

0010 0110

26

38

&

0010 0111

27

39

'

0010 1000

28

40

(

0010 1001

29

41

)

0010 1010

2A

42

*

0010 1011

2B

43

+

0010 1100

2C

44

,

0010 1101

2D

45

-

0010 1110

2E

46

.

0010 1111

2F

47

/

0011 0000

30

48

0

0011 0001

31

49

1

0011 0010

32

50

2

0011 0011

33

51

3

0011 0100

34

52

4

0011 0101

35

53

5

0011 0110

36

54

6

0011 0111

37

55

7

0011 1000

38

56

8

0011 1001

39

57

9

0011 1010

3A

58

:

0011 1011

3B

59

;

0011 1100

3C

60

<

0011 1101

3D

61

=

0011 1110

3E

62

>

0011 1111

3F

63

?

 

 

 

 

0100 0000

40

64

@

0100 0001

41

65

A

0100 0010

42

66

B

0100 0011

43

67

C

0100 0100

44

68

D

0100 0101

45

69

E

0100 0110

46

70

F

0100 0111

47

71

G

0100 1000

48

72

H

0100 1001

49

73

I

0100 1010

4A

74

J

0100 1011

4B

75

K

0100 1100

4C

76

L

0100 1101

4D

77

M

0100 1110

4E

78

N

0100 1111

4F

79

O

0101 0000

50

80

P

0101 0001

51

81

Q

0101 0010

52

82

R

0101 0011

53

83

S

0101 0100

54

84

T

0101 0101

55

85

U

0101 0110

56

86

V

0101 0111

57

87

W

0101 1000

58

88

X

0101 1001

59

89

Y

0101 1010

5A

90

Z

0101 1011

5B

91

[

0101 1100

5C

92

\

0101 1101

5D

93

]

0101 1110

5E

94

^

0101 1111

5F

95

_

 

 

 

 

0110 0000

60

96

`

0110 0001

61

97

a

0110 0010

62

98

b

0110 0011

63

99

c

0110 0100

64

100

d

0110 0101

65

101

e

0110 0110

66

102

f

0110 0111

67

103

g

0110 1000

68

104

h

0110 1001

69

105

i

0110 1010

6A

106

j

0110 1011

6B

107

k

0110 1100

6C

108

l

0110 1101

6D

109

m

0110 1110

6E

110

n

0110 1111

6F

111

o

0111 0000

70

112

p

0111 0001

71

113

q

0111 0010

72

114

r

0111 0011

73

115

s

0111 0100

74

116

t

0111 0101

75

117

u

0111 0110

76

118

v

0111 0111

77

119

w

0111 1000

78

120

x

0111 1001

79

121

y

0111 1010

7A

122

z

0111 1011

7B

123

{

0111 1100

7C

124

|

0111 1101

7D

125

}

0111 1110

7E

126

~