數字的unicode編碼對比「unicode碼錶轉換」

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

於是,ASCII碼誕生了。

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

ASCII碼

英文名稱:(American Standard Code for Information Interchange,美國信息互換標準代碼)

起源:ASCII碼是鼻祖,在1967年由美國發表規範標準。

前 128位:
一個ASCII字元佔用1個位元組(8bit)。因此,ASCII編碼能夠表示的最大字元數是256。事實上美國使用的英文字元就那麼幾個,所以前128個已足夠。這當中包含了控制字元、數字、大寫和小寫字母和其它一些標點符號。前128個屬於強制標準,各國必須遵循,一直沿用至今。

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和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和utf-8有何區別?ANSI和ASCII有何關聯?

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 個位元組。

如下表,編碼對應二進位:

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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的縮寫,它用來指明編碼,如下所示:

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

上面的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編碼。再次打開,顯示如下圖所示:

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

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

附上一個編碼位元組數表

「原」unicode和utf-8有何區別?ANSI和ASCII有何關聯?

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/274473.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-17 14:13
下一篇 2024-12-17 14:13

相關推薦

發表回復

登錄後才能評論