計算機運算和存儲使用的是二進制數,也就是0和1。這樣就需要一套標準,把英文字符對應成二進制數輸入到計算機,這樣才能被計算機識別。
於是,ASCII碼誕生了。

ASCII碼
英文名稱:(American Standard Code for Information Interchange,美國信息互換標準代碼)
起源:ASCII碼是鼻祖,在1967年由美國發表規範標準。
前 128位:
一個ASCII字符佔用1個字節(8bit)。因此,ASCII編碼能夠表示的最大字符數是256。事實上美國使用的英文字符就那麼幾個,所以前128個已足夠。這當中包含了控制字符、數字、大寫和小寫字母和其它一些標點符號。前128個屬於強制標準,各國必須遵循,一直沿用至今。

後 128位:
而最高位為1的後128個字符被稱為“擴展ASCII碼”,屬於非強制標準。當時,美國用它來存放英文的製表符、部分音標字符等等的一些其它符號。但是,美國萬萬沒想到是,這後128個“擴展ASCII碼”盡成為了其他國家的五花八門之地。

擴展ASCII碼:
既然後128字符並不是強制標準,於是,各個國家紛紛制定了屬於自己的文字編碼規範,中國也制定了自己的編碼規範GB2132,它是和ASCII碼兼容的一種編碼規範,事實上就是利用“擴展ASCII碼”沒有真正標準化這一點,把一個中文字符用兩個擴展ASCII字符來表示,也就是一個中文字符佔用2個字節。
局限問題:
在英語中,用前128個符號編碼便可以表示所有字母,但是用來表示其他語言,這128個符號是遠遠不夠的。比如,在法語中,字母上方有注音符號,這咋辦呢?於是,一些歐洲國家就自行決定,利用後128位編入新的符號。比如,法語中的é的編碼為130(二進制10000010)。這樣一來,一些歐洲國家也開始使用這種編碼方式,但最多也只有256個符號。
但是,這裡又出現了新的問題。不同的國家有不同的字母。因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。比如,130在法語編碼中代表了é,在希伯來語編碼中卻代表了字母Gimel (ג),在俄語編碼中又會代表另一個符號。但是不管怎樣,所有各國編碼方式中,0–127表示的符號都是一樣的,不同的是128–255的這一段 。
關於亞洲國家的文字種類繁多,使用的符號就更多了,光漢字就多達10萬種左右。一個字節僅僅只能表示256種符號,肯定是不夠用的,那就必須使用多個字節表達一個符號。比如,簡體中文常見的編碼方式是 GB2312,規定使用兩個字節表示一個漢字,所以理論上最多可以表示 256 x 256 = 65536 個漢字 。
可以看出,如果讓全世界都使用“ASCII碼”或是“擴展ASCII碼”,顯然存在着諸多局限性問題。
ANSI標準
英文名稱:(AMERICAN NATIONAL STANDARDS INSTITUTE: ANSI 美國國家標準學會)
起源:從1918年成立,到1969年正式命名為美國國家標準學會(ANSI)
ANSI定義:
ANSI是一種字符代碼,為使計算機支持更多語言,通常使用 0x00~0x7f 範圍的1 個字節來表示 1 個英文字符。超出此範圍的使用0x80~0xFFFF來編碼,比如:漢字 ‘中’ 在中文操作系統中,使用 2個字節來表示1個字符。
ANSI編碼:
不同的國家和地區制定了不同的標準,由此產生了 GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的編碼標準。這些使用多個字節來代表一個字符的各種漢字延伸編碼方式,稱為 ANSI 編碼。在簡體中文Windows操作系統中,ANSI 編碼代表 GB2312編碼;在繁體中文Windows操作系統中,ANSI編碼代表Big5;在日文Windows操作系統中,ANSI 編碼代表 JIS 編碼。
“ANSI編碼”和“ASCII編碼“有何關聯:
看到這裡你是否感覺“ANSI編碼”和“ASCII編碼”的概念有相似之處?!其實,ANSI編碼所定義的0x00~0x7f 範圍(0–127)的1 個字節來表示 1 個英文字符,即ASCII碼。而定義中使用0x80~0xFFFF範圍(128–35535)來編碼使用2個字節表示1個字符,即擴展ASCII碼。而且,不同 ANSI 編碼(即不同國家的擴展ASCII碼)之間互不兼容。當信息在國際間交流時,無法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。ANSI編碼表示英文字符時用一個字節,表示中文字符用兩個字節。
舉一個例子:
Windows記事本默認保存編碼是ANSI,這個大家可以在另存為窗口中看到可選擇的編碼方式。而這個ANSI編碼,它在英文操作系統下用的是ASCII碼,它在簡體中文操作系統下用的是GB2312,它在繁體中文操作系統下用的是Big5,等等諸如此類。
適用對象:
ANSI編碼作為中國以及部分亞太地區的多字符編碼格式,其Windows系統和macOS都是提供原生支持的。但在Linux下卻是UTF-8編碼大行其道,特別是開發者清一色都使用UTF-8編碼格式。這樣看來,普通用戶用ANSI編碼,因為他們無需理解什麼是ANSI編碼,而專業的開發者都以UTF-8編碼為主,開發者需要知道編碼的含義及應用場景,關於UTF-8具體後面會講到。
附圖

Unicode(統一碼)
非標準編碼產生的問題:
中國自己制定的GB2312隻是國家標準,而非國際標準,像台灣也自己制定一個Big5編碼,其他如韓國、日本等都有自己的編碼,這些通通不是國際標準。這種方法最大的問題就是,各國文字只適用於自己國家的編碼,不能通用在其他國家。
我們再來看看這個“擴展ASCII碼“,儘管沒有真正的標準化,可是PC里的ASCII碼還是有一個事實標準的(存放着英文製表符),所以早期非常多的軟件利用這些符號來畫表格。這樣的軟件用到中文系統中,這些表格符就會被誤認作中文字,破壞版面。並且,統計中英文混合字符串中的字數,也是頭疼的一件事,我們必須判斷這個字符是否是“擴展ASCII碼”,在邏輯上處理起來顯得比較複雜。
這時候,我們就知道,要真正解決中文問題,不能從“擴展ASCII”的角度入手,也不能僅靠中國一家來解決。而必須有一個全新的編碼系統,這個系統要能夠將中文、英文、法文、德文……等等全部的文字統一起來考慮,為每一個文字都分配一個單獨的編碼,這樣才不會有上面那種現象出現。
於是,Unicode誕生了:1990年研發,到1994年正式發布1.0版本,到2020年發布13.0版本。
兩套標準:
Unicode有兩套標準,一套叫UCS-2(Unicode-16),用2個字節為字符編碼,還有一套叫UCS-4(Unicode-32),用4個字節為字符編碼。
目前使用的是UCS-2,它能夠表示的字符數為2^16=65535,基本上能夠容納全部的歐美字符和絕大部分的亞洲字符。而UCS-4是為了防止將來2個字節不夠用才開發的。在Unicode里,全部的字符被一視同仁。漢字不再使用“兩個擴展ASCII”,而是使用“1個Unicode”。注意,如今的漢字是“一個字符”了,於是,拆字、統計字數這些問題也就自然而然地攻克了。
可是,這個世界不是理想的,不可能在一夜之間全部的系統都使用Unicode來處理字符,所以Unicode在誕生之日,就必須考慮一個嚴峻的問題,和ASCII字符集之間的不兼容問題。我們知道,ASCII字符是單個字節的,比方“A”的ASCII是65。而Unicode是雙字節的,比方“A”的Unicode是0065,這就造成了一個非常大的問題:以前處理ASCII的那套機制不能被用來處理Unicode了。
unicode定義和編碼規則:
廣義的 Unicode 是一個標準,定義了一個字符集以及一系列的編碼規則,即 Unicode 字符集和 UTF-8、UTF-16、UTF-32 等等編碼。所以,簡單來講,Unicode可以看作一種標準,它包含了世界上所有的字符,什麼語言、文字、符號統統包含在裡面。如果可以,你甚至可以理解為unicode全球統一字符集。但這個unicode全球統一字符集不能直接輸入到計算機中,所以需要一套編碼方式才能讓計算機認識,於是UTF-8、UTF-16、UTF-32 等等編碼產生了,使用這些編碼就可以在計算機中進行存儲了。
UTF-8,當今的王者:
UTF-8屬於Unicode的一種可變長度字符編碼,用1到4個字節表示,它可以表示Unicode全球統一字符集中的任何字符,且其編碼中的第一個字節仍與ASCII相容,在UTF-8編碼中一個英文佔1個字節,一個中文漢字佔3個字節。
舉一個例子:
既然Unicode 全球統一字符集為每一個字符分配一個碼位。就拿我們應用最廣泛的UTF-8來說(UTF-8 顧名思義,是一套以 8 位為一個編碼單位的可變長編碼),它將一個碼位編碼為 1 到 4 個字節。
如下表,編碼對應二進制:

例如「知」的碼位是 30693,記作 U+77E5(30693 的十六進制為 0x77E5)
根據上表中的編碼規則,「知」字的碼位 U+77E5 屬於第三行的範圍,中文漢字使用了3個字。

我們再來看一個具體一點的例子(來自互聯網):
windows操作系統記事本另存為時,有四種編碼:

我們把四種編碼分別存為4個文件:

我們用VC++6.0或Visual Studio以二進制方式打開這4個文件,如下圖所示:

1)ANSI編碼
A.txt有四個字節:B1 E0 C2 EB。使用了GBK編碼,其中B1 E0是指”編”,C2 EB指是”碼”。
所以,記事本里的ANSI編碼,在簡體中文操作系統中,用的就是GBK編碼。在繁體中文操作系統中,用的就是Big5編碼……
2)UTF16BE編碼
UB.txt有六個字節:FE FF 7F 16 78 01。其中FE FF是BOM(Byte Order Mark)。使用了Unicode字符集的UTF-16編碼,0x7F16是指”編”,0x7801是指”碼”。
UTF16BE編碼是16位(2字節)的Unicode字符集編碼,BE表示big endian,即高位字節在前,低位字節在後。0x7F16的高位字節是7F,低位字節是16,UTF16BE編碼就是7F 16。
3)UTF16LE編碼
U.txt有六個字節:FF FE 16 7F 01 78。其中FF FE是BOM。使用了Unicode字符集的UTF-16編碼,0x7F16是指”編”,0x7801是指”碼”。
UTF16LE編碼是16位(2字節)的Unicode編碼,LE表示little endian,即低位字節在前,高位字節在後。0x7F16的高位字節是7F,低位字節是16,UTF16LE編碼就是16 7F。
由此可見:UTF16LE與UTF16BE只是高低位字節交換了一下而已。
4)UTF-8編碼
U8.txt有九個字節:EF BB BF E7 BC 96 E7 A0 81。其中EF BB BF是BOM。使用了Unicode字符集的UTF-8編碼,E7 BC 96是指”編”,E7 A0 81是指”碼”。
5) BOM
BOM是Byte Order Mark的縮寫,它用來指明編碼,如下所示:

上面的FE FF和FF FE正好逆序,這也就是Byte Order Mark(字節順序標記)的來由吧。
6) 亂碼
windows記事本是通過BOM來區分不同編碼,為什麼ANSI不用BOM?原因在於——向下兼容。從DOS到Win98再到如今的Win10,記事本默認都是ANSI編碼,從沒考慮過加BOM。所以BOM對於windows記事本來說是沒必要的,也是無關緊要的。
通過BOM來區分各種編碼,是一個非常好的方法。不過,沒有歷史包袱的Linux不買賬——Linux默認使用UTF-8編碼,而且是沒有BOM的UTF-8編碼。
為了能夠打開Linux生成的沒有BOM的UTF-8編碼文件,記事本在打開沒有BOM的文本文件時,會對其進行檢查。如果所有編碼符合UTF-8,就以UTF-8編碼打開。
我們把Linux下生成的UTF-8編碼的txt拿到windows下,可以正常打開和顯示,並在windows下把內容”編碼”替換為”聯通”,另存為選ANSI編碼。再次打開,顯示如下圖所示:

使用VC++6.0打開這個文件,一切正常,如下圖所示:

windows下記事本顯示亂碼,是因為它會把”聯通”的GBK編碼C1 AA CD A8當做UTF-8編碼進行顯示。而VC++6.0沒有顯示亂碼,是因為它不支持UTF-8編碼,只支持ANSI編碼。
附上一個編碼字節數表

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/274473.html
微信掃一掃
支付寶掃一掃