字符编码(ASCII、ANSI、GB23十二、UTF-8等)系统梳理


引言

在显示器上看见的文字、图片等信息在电脑里面其实并非咱们看见的样子,即便你知道全部信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方表明数字1,凹的地方表明数字0。硬盘只能用0和1来表示全部文字、图片等信息。那么字母”A”在硬盘上是如何存储的呢?数据库

可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。好比小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,因而小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不一样的编码表。小张用的编码表是ASCII,ASCII编码表把26个字母都一一的对应到2进制1和0上;小王用的编码表多是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不一样。windows

通常地说,开放的操做系统(LINUX 、WINDOWS等)采用ASCII 编码,而大型主机系统(MVS、OS/390等)采用EBCDIC 编码。在发送数据给对方前,须要事先告知对方本身所使用的编码,或者经过转码,使不一样编码方案的两个系统可沟通自如。数组


ASCII编码

ASCII是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其余西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646ui

请注意,ASCII是American Standard Code for Information Interchange缩写,而不是ASC2,有不少人在这个地方产生误解。编码

ASCII 码使用指定的7 位或8 位二进制数组合来表示128或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用7 位二进制数来表示全部的大写和小写字母,数字0 到九、标点符号,以及在美式英语中使用的特殊控制字符。其中:spa

0~31及127(共33个)是控制字符或通讯专用字符(其他为可显示字符操作系统

32~126(共95个)是字符(32是空格),其中48~57为0到9十个阿拉伯数字。设计

65~90为26个大写英文字母,97~122号为26个小写英文字母,其他为一些标点符号、运算符号等。code

同时还要注意,在标准ASCII中,其最高位(b7)用做奇偶校验位。所谓奇偶校验,是指在代码传送过程当中用来检验是否出现错误的一种方法,通常分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。orm

后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展ASCII 码容许将每一个字符的第8 位用于肯定附加的128 个特殊符号字符、外来语字母和图形符号。

标准ASCII码以下:

二进制

十进制

十六进制

缩写/字符

解释

 

0000 0000

0

00

NUL(null)

空字符

 

0000 0001

1

01

SOH(start of headline)

标题开始

 

0000 0010

2

02

STX (start of text)

正文开始

 

0000 0011

3

03

ETX (end of text)

正文结束

 

0000 0100

4

04

EOT (end of transmission)

传输结束

 

0000 0101

5

05

ENQ (enquiry)

请求

 

0000 0110

6

06

ACK (acknowledge)

收到通知

 

0000 0111

7

07

BEL (bell)

响铃

 

0000 1000

8

08

BS (backspace)

退格

 

0000 1001

9

09

HT (horizontal tab)

水平制表符

 

0000 1010

10

0A

LF (NL line feed, new line)

换行键

 

0000 1011

11

0B

VT (vertical tab)

垂直制表符

 

0000 1100

12

0C

FF (NP form feed, new page)

换页键

 

0000 1101

13

0D

CR (carriage return)

回车键

 

0000 1110

14

0E

SO (shift out)

不用切换

 

0000 1111

15

0F

SI (shift in)

启用切换

 

0001 0000

16

10

DLE (data link escape)

数据链路转义

 

0001 0001

17

11

DC1 (device control 1)

设备控制1

 

0001 0010

18

12

DC2 (device control 2)

设备控制2

 

0001 0011

19

13

DC3 (device control 3)

设备控制3

 

0001 0100

20

14

DC4 (device control 4)

设备控制4

 

0001 0101

21

15

NAK (negative acknowledge)

拒绝接收

 

0001 0110

22

16

SYN (synchronous idle)

同步空闲

 

0001 0111

23

17

ETB (end of trans. block)

传输块结束

 

0001 1000

24

18

CAN (cancel)

取消

 

0001 1001

25

19

EM (end of medium)

介质中断

 

0001 1010

26

1A

SUB (substitute)

替补

 

0001 1011

27

1B

ESC (escape)

换码(溢出)

 

0001 1100

28

1C

FS (file separator)

文件分割符

 

0001 1101

29

1D

GS (group separator)

分组符

 

0001 1110

30

1E

RS (record separator)

记录分离符

 

0001 1111

31

1F

US (unit separator)

单元分隔符

 

0010 0000

32

20

(space)

空格

 

0010 0001

33

21

!

 

 

0010 0010

34

22

"

 

 

0010 0011

35

23

#

 

 

0010 0100

36

24

$

 

 

0010 0101

37

25

%

 

 

0010 0110

38

26

&

 

 

0010 0111

39

27

'

 

 

0010 1000

40

28

(

 

 

0010 1001

41

29

)

 

 

0010 1010

42

2A

*

 

 

0010 1011

43

2B

+

 

 

0010 1100

44

2C

,

 

 

0010 1101

45

2D

-

 

 

0010 1110

46

2E

.

 

 

00101111

47

2F

/

 

 

00110000

48

30

0

 

 

00110001

49

31

1

 

 

00110010

50

32

2

 

 

00110011

51

33

3

 

 

00110100

52

34

4

 

 

00110101

53

35

5

 

 

00110110

54

36

6

 

 

00110111

55

37

7

 

 

00111000

56

38

8

 

 

00111001

57

39

9

 

 

00111010

58

3A

:

 

 

00111011

59

3B

;

 

 

00111100

60

3C

 

 

00111101

61

3D

=

 

 

00111110

62

3E

 

 

00111111

63

3F

?

 

 

01000000

64

40

@

 

 

01000001

65

41

A

 

 

01000010

66

42

B

 

 

01000011

67

43

C

 

 

01000100

68

44

D

 

 

01000101

69

45

E

 

 

01000110

70

46

F

 

 

01000111

71

47

G

 

 

01001000

72

48

H

 

 

01001001

73

49

I

 

 

01001010

74

4A

J

 

 

01001011

75

4B

K

 

 

01001100

76

4C

L

 

 

01001101

77

4D

M

 

 

01001110

78

4E

N

 

 

01001111

79

4F

O

 

 

01010000

80

50

P

 

 

01010001

81

51

Q

 

 

01010010

82

52

R

 

 

01010011

83

53

S

 

 

01010100

84

54

T

 

 

01010101

85

55

U

 

 

01010110

86

56

V

 

 

01010111

87

57

W

 

 

01011000

88

58

X

 

 

01011001

89

59

Y

 

 

01011010

90

5A

Z

 

 

01011011

91

5B

[

 

 

01011100

92

5C

\

 

 

01011101

93

5D

]

 

 

01011110

94

5E

^

 

 

01011111

95

5F

_

 

 

01100000

96

60

`

 

 

01100001

97

61

a

 

 

01100010

98

62

b

 

 

01100011

99

63

c

 

 

01100100

100

64

d

 

 

01100101

101

65

e

 

 

01100110

102

66

f

 

 

01100111

103

67

g

 

 

01101000

104

68

h

 

 

01101001

105

69

i

 

 

01101010

106

6A

j

 

 

01101011

107

6B

k

 

 

01101100

108

6C

l

 

 

01101101

109

6D

m

 

 

01101110

110

6E

n

 

 

01101111

111

6F

o

 

 

01110000

112

70

p

 

 

01110001

113

71

q

 

 

01110010

114

72

r

 

 

01110011

115

73

s

 

 

01110100

116

74

t

 

 

01110101

117

75

u

 

 

01110110

118

76

v

 

 

01110111

119

77

w

 

 

01111000

120

78

x

 

 

01111001

121

79

y

 

 

01111010

122

7A

z

 

 

01111011

123

7B

{

 

 

01111100

124

7C

|

 

 

01111101

125

7D

}

 

 

01111110

126

7E

~

 

 

01111111

127

7F

DEL (delete)

删除

 


ISO-8859-1编码

ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间彻底和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。

ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。

HTML 4.01 支持 ISO 8859-1(Latin-1) 字符集。

ISO-8859-1 的较低部分(从 1 到 127 之间的代码)是最初的7位 ASCII。

ISO-8859-1 的较高部分(从 160 到 255 之间的代码)全都有实体名称。

由于ISO-8859-1编码范围使用了单字节内的全部空间(即8位,0-255),在支持ISO-8859-1的系统中传输和存储其余任何编码的字节流都不会被抛弃。换言之,把其余任何编码的字节流看成ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

Latin1是ISO-8859-1的别名,有些环境下写做Latin-1。


ANSI 标准

ASCII是美国标准,因此它不能良好知足其它国家的须要。例如英国的英镑符号(£),拉丁语字母表重音符号,使用斯拉夫字母表的希腊语、希伯来语、阿拉伯语和俄语,还有汉字系统的中国象形汉字,日本语和朝鲜语等等。

多字节字符集 (MBCS,Multi-ByteChactacter Set) 是一种旧的方式以支持没法用单字节表示的字符集(如日文和中文)的方法。最多见的 MBCS 实现是双字节字符集 (DBCS,Double-Byte CharacterSet)。在DBCS系列标准里,最大的特色是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,所以程序为了支持中文处理,必需要注意字串里的每个字节的值,若是这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。

为了扩充ASCII编码,以用于显示本国的语言,不一样的国家和地区制定了不一样的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来表明一个字符的各类延伸编码方式,称为ANSI 编码(AmericanNational Standards Institute,美国国家标准学会),也称为MBCS编码。在简体中文系统下,ANSI编码表明 GB2312 编码,在日文操做系统下,ANSI 编码表明 JIS 编码,因此在中文 windows下要转码成gb2312,gbk只须要把文本保存为ANSI 编码便可。

不一样 ANSI 编码之间互不兼容,当信息在国际间交流时,没法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。一个很大的缺点是,同一个编码值,在不一样的编码体系里表明着不一样的字。这样就容易形成混乱。致使了unicode码的诞生。

固然对于ANSI编码而言,0x00~0x7F(即十进制下的0到127)之间的字符,依旧是1个字节表明1个字符。这一点是ASNI编码与Unicode编码之间最大也最明显的区别。


GB2312编码

GB2312 是ANSI编码里的一种,对ANSI编码最初始的ASCII编码进行扩充,为了知足国内在计算机中使用汉字的须要,中国国家标准总局发布了一系列的汉字字符集国家标准编码,统称为GB码,或国标码。其中最有影响的是于1980年发布的《信息交换用汉字编码字符集基本集》,标准号为GB 2312-1980,因其使用很是广泛,也常被通称为国标码。GB2312编码通行于我国内地;新加坡等地也采用此编码。几乎全部的中文系统和国际化的软件都支持GB 2312。

一个小于127的字符的意义与原来相同,但两个大于127的字符连在一块儿时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样咱们就能够组合出大约7000多个简体汉字了。在这些编码里,咱们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里原本就有的数字、标点、字母都通通从新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号如下的那些就叫"半角"字符了。

为避免同西文的存储发生冲突,GB2312字符在进行存储时,经过将原来的每一个字节第8bit设置为1同西文加以区别,若是第8bit为0,则表示西文字符,不然表示GB2312中的字符

GB2312是一个简体中文字符集,由6763个经常使用汉字和682个全角的非汉字字符组成。其中汉字根据使用的频率分为两级。一级汉字3755个,二级汉字3008个。


GBK编码

GB2312的出现,基本知足了汉字的计算机处理须要,但对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这致使了后来GBK及GB 18030汉字字符集的出现。GBK是对GB2312的扩展

GBK采用双字节表示,整体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,剔除 xx7F一条线。总计23940 个码位,GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。


BIG-5编码

BIG-5码,又称为大五码或者五大码,是通行于台湾、香港地区的一个繁体字编码方案。至关于港台地区的GB2312编码,也是ANSI编码的一种

“五大码(大五码)”(Big5)是在1984年由台湾13家厂商与台湾地区财团法人信息工业策进会为五大中文套装软件(宏碁、神通、佳佳、零壹、大众)所设计的中文内码,因此就称为Big5中文内码


Unicode字符集

如上ANSI编码条例中所述,世界上存在着多种编码方式,在ANSI编码下,同一个编码值,在不一样的编码体系里表明着不一样的字。在简体中文系统下,ANSI 编码表明 GB2312 编码,在日文操做系统下,ANSI 编码表明 JIS 编码,可能最终显示的是中文,也可能显示的是日文。在ANSI编码体系下,要想打开一个文本文件,不但要知道它的编码方式,还要安装有对应编码表,不然就可能没法读取或出现乱码。为何电子邮件和网页都常常会出现乱码,就是由于信息的提供者多是日文的ANSI编码体系和信息的读取者多是中文的编码体系,他们对同一个二进制编码值进行显示,采用了不一样的编码,致使乱码。这个问题促使了unicode码的诞生。

若是有一种编码,将世界上全部的符号都归入其中,不管是英文、日文、仍是中文等,你们都使用这个编码表,就不会出现编码不匹配现象。每一个符号对应一个惟一的编码,乱码问题就不存在了。这就是Unicode编码。

通用字符集(UniversalCharacter Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC10646)标准所定义的标准字符集。编码层面上,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。     UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。

Unicode固然是一个很大的集合,如今的规模能够容纳100多万个符号。每一个符号的编码都不同,好比,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6C49。

须要注意的是,Unicode只是一个字符集,它只规定了符号与二进制代码之间的对应关系,却没有规定这个二进制代码应该如何存储

好比,汉字"严"的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少须要2个字节。表示其余更大的符号,可能须要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,咱们已经知道,英文字母只用一个字节表示就够了,若是Unicode统一规定,每一个符号用三个或四个字节表示,那么每一个英文字母前都必然有二到三个字节是0,这对于存储来讲是极大的浪费,文本文件的大小会所以大出二三倍,这是没法接受的。

它们形成的结果是:1)出现了Unicode的多种存储方式,也就是说有许多种不一样的二进制格式,能够用来表示Unicode。2)Unicode在很长一段时间内没法推广,直到互联网的出现。


UTF-8编码

UTF-8是Unicode的实现方式之一。

UTF-8(UCSTransformation Format 8bit)就是在互联网上使用最广的一种Unicode的实现方式。其余实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上用的不多。

UTF-8最大的一个特色,就是它是一种变长的编码方式。它可使用1~4个字节表示一个符号,根据不一样的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。所以对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一概设为10。剩下的没有说起的二进制位,所有为这个符号的unicode码。

从Unicode到UTF-8的编码方式以下:

Unicode编码(十六进制)

UTF-8 字节流(二进制)

000000 - 00007F

0xxxxxxx

000080 - 0007FF

110xxxxx 10xxxxxx

000800 - 00FFFF

1110xxxx 10xxxxxx 10xxxxxx

010000 - 10FFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

例如,“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:

1110xxxx10xxxxxx 10xxxxxx。

将0x6C49写成二进制是:

0110 1100 01001001,

用这个比特流依次代替模板中的x,获得:

1110011010110001 10001001

即E6 B1 89就是“汉”的UTF-8码。

 

不少细心的人会发现,新建一个空的文本文件,用记事本打开(必须是Windows自带的记事本),只输入“联通”二字保存关闭,再从新打开时将是乱码。

在保存这个操做中,windows默认保存的编码是ANSI(实际上应该是GBK)。

这样联通这两个字的二进制内码是:(一个字占两个字节)

c1   1100 0001

aa   1010 1010

cd   1100 1101

a8   1010 1000

 

巧合的地方在于“联通”这两个字的ANSI编码符合UTF-8编码的第二个模板。

当txt文档中一切字符都在 C0≤AA(第一个字节)≤DF 80≤BB(第二个字节)≤BF 这个范围时,notepad都没法确认文档的格式,自动依照UTF-8格式来解码。而“联通”就是C1 AA CD A8,恰好在上面的范围内,因此不能正常显现。

假如保存时选择Unicode、Unicode (BigEndian)、UTF-8编码,就正常了。此外,假如以ANSI编码保存含有某些特别符号的文本文档,再次打开后符号也会变成英文问号。


Little endian和Big endian

UTF-八、UTF-1六、UTF-32等显现了Unicode的编码方式,可是还有一个问题,编码后应该如何存储?

这里就要引出两个名词:

LE(littleendian):小字节字节序,意思就是一个单元在计算机中的存放时按照低位在前(低地址),高位在后(高地址)的模式存放。

BE(big endian):大字节字节序,和LE相反,是高位在前,低位在后。

好比一个unicode编码为:0x006C49,若是是LE,那么在文件中的存放顺序应该是:49 6c 00

若是是BE ,那么顺序应该是:00 6c49

这两个古怪的名称来自英国做家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争原由是人们争论,吃鸡蛋时到底是从大头(Big-Endian)敲开仍是从小头(Little-Endian)敲开。为了这件事情,先后爆发了六次战争,一个皇帝送了命,另外一个皇帝丢了王位。

那么很天然的,就会出现另外一个一个问题:计算机怎么知道某一个文件到底采用哪种方式编码?

Unicode规范中定义,每个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫作"零宽度非换行空格"(ZERO WIDTHNO-BREAK SPACE),用FEFF表示。这正好是两个字节,并且FF比FE大1。这些编码在unicode 中是没有使用的,因此不用担忧会冲突。

这种方式叫作BOM(Byte Order Mark)头。意思是字节序标志头。经过它基本能肯定编码格式和字节序。

若是一个文本文件的头两个字节是FE FF,就表示该文件采用大字节字节序;若是头两个字节是FF FE,就表示该文件采用小字节字节序。

BOM检测不能保证100%准确,只能经过编码范围从几率上来检查,虽然准确度仍是比较高,可是不能保证100%。因此,时常看到检测错误的软件,也不奇怪了。

相关文章
相关标签/搜索