字符編碼(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%。因此,時常看到檢測錯誤的軟件,也不奇怪了。

相關文章
相關標籤/搜索