字符集編碼(上):Unicode 之前

林子er發表於2022-02-17

計算機起初是設計用來做數學計算的,Computer 一詞英文原意是“計算員”——在計算機發明之前,計算員是一個獨立的職業,專門做各種數學用表的計算,如測量和天文領域的三角函式表、對數表,航海領域的航海天文歷等。

計算機發明後不久,人們發現,這玩意除了能當計算員,還能當文員,用來處理人類社會的非數字資訊。然而,計算機在設計上是隻認識數字的(具體說是隻認識二進位制數字),要想讓它能夠識別並處理人類符號,就必須採取某種翻譯手段,在計算機的二進位制數字和人類的符號之間做雙向轉換。

這種字元-數字的對映(轉換)關係本質上就是一張查詢表,在理論上是很簡單的。我們先給人類的每個字元分配一個獨一無二的編號(character code,字元編碼),如圖:

image-20220215161831963

然後通過外設(鍵盤)將字元輸入到計算機中,比如我們鍵盤上針對A、B、C分別都有按鍵。當我們按下“A”後,計算機通過查詢表得知該字元的編碼是十進位制 1,便使用二進位制 00000001 在內部表示和儲存起來。

光儲存還不行,我們還要將計算機中的字元(編號)顯示或列印出來,所以還涉及到字型檔。在顯示器上顯示某個字元,本質上是在一個n*n 的畫素點陣中,讓某些位置的畫素設定為黑色(用 1 表示),其它位置為白色(用 0 表示),比如中文“你”的點陣圖(注意不同字型檔的點陣圖不同):

img

這樣一個 16*16 的畫素矩陣,需要 16 * 16 / 8 = 32 位元組的空間來表示,右邊的“字模資訊”稱為字形編碼。不同的字型檔(如宋體、黑體)對同一個字元的字形編碼是不同的。

這裡每個畫素只需要黑、白兩種顏色,只需要一個位就行了,如果是彩色,則理論上需要 3 位元組(RGB)來表示(當然這裡沒考慮壓縮演算法)。

所以這裡涉及到另一張查詢表:字元編碼-字形編碼的對映關係:

image-20220215161942714

計算機根據使用者指定的字型檔從中查出字元編碼對應的字形編碼值,輸送給相應的圖形處理程式進而顯示出來相應的字元。

整個輸入-轉碼儲存-輸出(顯示/列印)的流程簡單表示如下:

image-20220215153322852

對於英文字元,直接在鍵盤上敲就行了,對於其他字元比如中文,則不是那麼直觀,因為鍵盤無論如何也放不下那麼多漢字,所以又要用到另一層轉換。我們稱計算機內部那個字元編碼稱為內碼,而外部使用者輸入用到的叫做外碼,比如中文輸入法用到的外碼有拼音、五筆碼、倉頡碼等,對於這種情況,還需要做一次外碼到內碼的對映。

文書處理系統需要考慮的事情非常多,絕非簡單進行編碼對映就行。比如英文單詞的換行、英文單詞的大小寫、中文的橫排豎排、阿拉伯語的連字處理等,文書處理系統需要能夠正確處理特定語言上下文。

我們接下來重點講上圖中“字元編碼”這塊。


源於美國

用今天的眼光看,這世界存在各種各樣的字元編碼標準,什麼ASCII、 ISO-8859-1、GBK、Big5、Unicode 等——你有沒有想過,單單一個字元編碼,為啥會有這麼多標準?這不是成心讓程式設計師頭大嗎?

現實中的標準從來都不是由某權威機構事先制定的,而是一些公司因自身需求(市場擴充需要)而發明出來一套遊戲規則。每家公司都根據自身情況發明自己的遊戲規則,各家之間規則彼此不同,自己玩沒事,跑到一起玩(互操作)就啞巴了。於是要麼標準制定機構(如國家標準委員會、ISO 等)站出來,要麼幾家龍頭企業湊到一起成立個某某聯盟,總之大家都有一個目標:統一遊戲規則。

套用魯迅先生一句話就是:這世間本沒有標準,玩得人多了,便成了標準。

只有從這個角度看問題,才能理解為啥會存在那麼多字符集編碼標準,為啥要有 Unicode,而 Unicode 的一些實現為啥怪怪的。

1964 年,IBM 推出其劃時代的大型機 System/360(怎麼個劃時代請自行百度),為該大型機設計的字符集編碼標準叫 EBCDIC(Extended Binary Coded Decimal Interchange Code,擴充套件二進位制編碼的十進位制交換碼),這是一個單位元組編碼方案,囊括了一些控制字元、數字、常用標點、大小寫英文字母:

img

EBCDIC 編碼。圖片來自百度百科

圖中行號表示位元組高 4 位,列號表示位元組低 4 位,行、列分別是十六進位制 0~F,如 0x81 表示 a,0xC1 表示 A。注意表中英文單詞不是連續的,這給程式處理帶來些許麻煩。

4 年後,美國國家標準學會 ANSI(American National Standard Institute) 於 1968 年釋出了著名的 ASCII(American Standard Code for Information Interchange美國資訊交換標準碼) 編碼標準。ASCII 和 EBCDIC 一樣是單位元組編碼,不過它吸取了 EBCDIC 的經驗教訓,給英文單詞分配了連續的編碼,方便程式處理。

img

ASCII 編碼(注意該表是列表示位元組高 4 位)。圖片來自百度百科

其中前 32 個(031)是不可見的控制字元,32126 是可見字元,127 是 DELETE 命令(鍵盤上的 DEL 鍵)。

ASCII 和 EBCDIC 編碼相比,除了拉丁字母是連續排列的以外,ASCII 只用了一個位元組的低 7 位,最高位永遠是 0。所以 ASCII 最多能表示 2^7 = 128 個字元,這對於當時美國來說已經足夠了。

別小看這個最高位的 0,這可以說是 ASCII 設計得最成功的一個地方,後面我們討論其它編碼規範的時候你會發現,正是有了這個最高位的 0 作為 ASCII 的標識,其它編碼規範才能對 ASCII 碼無縫相容,這進而使得 ASCII 被廣泛接受,並於 1972 年被 ISO/IEC 採用作為國際標準(ISO/IEC 646),直至今日仍然是世界上最基礎、最重要、使用最廣泛的字元編碼標準之一。

EBCDIC 雖然用完了全部 8 個位元,理論上可以對 2^8 = 256 個字元進行編碼,但實際上其中有很多編號並沒有對應的字元,如圖中所示,其中有幾塊不連續的“空洞地帶”,其編碼遠沒有 ASCII 緊湊。由於 EBCDIC 的一些弊端,在 ANSI 推出 ASCII 編碼標準後,IBM 在其後來的個人計算機(PC)和工作站作業系統中不再使用自家的 EBCDIC,而是使用 ASCII。


個人計算機

1971 年,英特爾釋出了世界上第一款微處理器 4004。這是一塊 4 位微處理器(現在都是 64 位了),10 微米的工藝(現在是 10 奈米以下工藝),尺寸為 3*4mm,工作頻率為 108KHz,每秒運算 6 萬次。

img

第一枚微處理器 Intel 4004

用今天的標準看,這玩意算力不高,但它的突破性在於尺寸,只有幾毫米見方,用當時的眼光看,可以用“微”來形容。

CPU 尺寸的大大縮小使得計算機體積大大降低,讓計算機能夠放在個人辦公桌上,而不是隻能呆在專門的機房裡(想想第一臺電子計算機 ENIAC 佔地 170 平米,你我的房子都裝不下)。另一個(但同樣重要的)結果是使得計算機的生產成本大大降低——這兩點讓普通公司和個人擁有計算機成為可能。

因而在微處理器出世後的七八十年代,是個人計算機的井噴年代。

1975 年愛德華·羅伯茨的 MITS 公司製造了世界上第一臺微型計算機 Altiar 8800售價僅為 397 美元(IBM 大型機 System/360 售價在 300 萬美元左右)。

img

第一臺微型計算機 Altiar 8800

注意:關於誰是第一臺個人計算機、第一臺微型計算機的說法是有爭議的(甚至包括微處理器也是如此),很多公司都說自己是第一,所以如果在其他地方看到不同的答案不要大驚小怪。

另外,雖然今天我們覺得個人擁有計算機是再正常不過的事情(沒有才不正常),但 20 世紀 70 年代早期人們可不這樣想,很多公司的第一反應是:個人要計算機幹嘛?很多公司由於認知上的侷限而錯失 PC 浪潮(比如施樂)。

1975年,比爾·蓋茨和保羅·艾倫創辦微軟。

1976年,史蒂夫·賈伯斯和史蒂夫·沃茲尼亞克創辦蘋果。

1981 年,IBM PC 問世。IBM PC 對整個行業產生了深遠影響。各大公司紛紛批量購入,從此個人電腦在辦公中發揮了越來越重要的作用。IBM PC 使用了微軟開發的 MS-DOS 作業系統,微軟隨之崛起。

img

1981 年釋出的 IBM PC

——等等,我們不是要聊字元編碼嗎,怎麼聊起個人計算機了?

如果沒有個人計算機的普及,世界上壓根不會出現那麼多字符集編碼,甚至不需要 Unicode。

像 System/360 那樣的大型機,一臺幾百萬美元(摺合現在要2000多萬美元),只有像航天局、銀行、航空公司等才需要用到,小公司和個人消費者怎麼也不會買——這種情況下,即便需要多語言編碼標準,也不會湧現那麼多的字符集,甚至很可能不會出現像 Unicode 這樣的統一編碼標準。

正是個人計算機的普及使得計算機在全世界範圍內變成了日常辦公用品,而軟硬體製造商在國際化過程中便必然面臨一個問題:原先的 ASCII 編碼標準無法表示其他國家的語言符號。


歐洲

製造商們在進入歐洲市場的時候就遇到了麻煩。

歐洲的主流語言雖然也是用拉丁字母,但卻存在很多擴充套件體,比如法語的 é,挪威語中的 Å,都無法用 ASCII 表示。

於是這些公司的技術人員就發揮自己的聰明才幹。大家發現,ASCII 編碼位元組中,最高位是沒有用到的(總是 0),既然這樣,為何不把這一位用起來呢,這樣能表達的字元數又多了 128 個,對於歐洲主流語言足夠了。

於是,各公司開始在 ASCII 的基礎上擴充套件出自己的字符集:當最高位是 0 的時候仍然表示原先的 ASCII 字元不變,當最高位是 1 時表示擴充套件字元——這樣既完美相容了原先的 ASCII,又能表達歐洲國家特定字元。比如 IBM 的 codepage 437 用來編碼歐洲主要語言字元(主要是西歐字元),codepage 852 編碼東歐國家的拉丁字母,codepage 855 編碼西里爾字元(如俄語)。微軟為 Windows 制定了 codepage 1252 用於編碼西歐字元。蘋果、施樂等也都在制定自己的 codepage 標準。

這裡存在兩個問題,一是各個公司各自制定自己的擴充套件編碼,相互之間互不相容;二是即便加上 128 個字元仍然無法表達所有的歐洲字元。

為了解決這兩個問題,國際標準化組織 ISO 和 IEC 聯合制定了一組標準叫 ISO/IEC 8859(簡稱 ISO 8859)。注意 ISO 8859 並不是一套具體的字符集編碼標準,而是一組字符集的合稱,稱為 ISO/IEC 8859-n,n=1,2,3,...,15,16(其中12未定義,所以共15個)。

這些字符集編碼標準都是單位元組編碼,前128 個字元編碼(最高位為 0)和 ASCII 一樣,後 128 個字元各自分配給不同的語系。ISO 8859 的各編碼都相容 ASCII,但彼此互不相容(即 0~127 範圍的大家都表示相同的字元,128~255 的各自表示各自體系裡面的字元)。

其中使用最廣泛的是 ISO/IEC 8859-1,又稱 latin 1,收錄了西歐常用字元,包括德語、義大利語、葡萄牙語、西班牙語等(由於 latin 1 中沒有法語的 œ、Œ、Ÿ,所以法語用的 ISO 8859-15 字符集)。

image-20220216170022100

ISO/IEC 8859-1 字符集,注意 007F 之前和 ASCII 是一致的

上文說的字元 Å 在此處用 00C5 表示。

其餘從 ISO 8859-2 到 ISO 8859-16 收錄字元如下(部分):

ISO/IEC 8859-1 (Latin-1) - 西歐語言
ISO/IEC 8859-2 (Latin-2) - 中歐語言
ISO/IEC 8859-3 (Latin-3) - 南歐語言。
ISO/IEC 8859-4 (Latin-4) - 北歐語言
ISO/IEC 8859-5 (Cyrillic) - 斯拉夫語言
ISO/IEC 8859-6 (Arabic) - 阿拉伯語
ISO/IEC 8859-7 (Greek) - 希臘語

......


東亞

當這些廠商進入東亞市場時,更頭大。

在歐洲,好歹能用 ASCII 高位保留的那個位元組搞出個 ISO 8859 系列標準來,然而當他們面對幾萬個漢字時,一臉懵逼。

對於中日韓這種表意文字,單位元組編碼根本行不通,要用兩個位元組。日語方面制定了 Shift JIS 標準;繁體中文則由臺灣相關行業協會於 1984 年制定了 Big5 標準;簡體中文由中國國家標準總局於 1980 年制定了 GB 2312。


GB 碼

作為中國大陸公民,這裡稍微深入聊下 GB 系列編碼標準。

GB 2312:

最初的標準是《資訊交換用漢字編碼字符集》,由中國國家標準總局於 1980年釋出、1981 年 5 月 1 日開始實施的一套國家標準,標準號為 GB 2312-1980,共收錄 6763 個漢字,另外還收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裡爾字母在內的 682 個字元。

GB 2312 是雙位元組編碼。為了相容 ASCII 碼,GB 2312 規定,漢字必須由兩個值大於 127(最高位是 1)的位元組來表示;反過來說,如果一個位元組的值小於等於 127(最高位是 0),則其和 ASCII 碼錶示的字元相同(也就是此時就是 ASCII 碼)。

也就是說,在 GB 2312 裡面,英文字母(以及 ASCII 中的標點)佔 1 個位元組,漢字佔 2 個位元組。

我們用 python 程式驗證下:

>>> bytes("A", "GB 2312")
b'A'
>>> bytes("啊", "GB 2312")
b'\xb0\xa1'

上面字母“A”佔 1 個位元組,字元“啊”佔了兩個位元組(位元組值為 B0 A1,兩個位元組的最高位都是 1,其中 B0 叫高位位元組,A1 叫低位位元組)。

也就是說,GB 2312 屬於變長編碼,用 1~2 個位元組表示字元,而位元組最高位的值決定了字元佔用的位元組數。

img

GB 2312 編碼表(部分)

注意看在 GB 2312 中,“(1)”、“(一)” 這種組合字元都分配了單獨的編碼(即將它們視為一個字元而不是多字元組合), 這影響了後面 Unicode 的字符集設計。

區位碼:

GB 2312 採用區位碼的方式編碼。這種編碼方式將一個矩形區域劃分成 94 行 × 94 列,形成 94 × 94 共 8836 個格子,然後將字元填入這些格子中。

行和列分別從 1 開始往後編號,行叫做,列叫做,這樣形成 1~94 個區,每個區有 94 個位,其中的字元用區號+位號來表示。

image-20220216210126036

區位矩陣示意圖。注意圖中區位編號是用十進位制表示的

其中:

  • 01~09區(682個):特殊符號、數字、英文字元、製表符等,包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裡爾字母等在內的682個全形字元;

  • 10~15區:空區,留待擴充套件;

  • 16~55區(3755個):常用漢字(也稱一級漢字),按拼音排序;

  • 56~87區(3008個):非常用漢字(也稱二級漢字),按部首/筆畫排序;

  • 88~94區:空區,留待擴充套件。

例如“啊”字的區號是 16,位號是 01,區位號用十六進位制表示就是 10 01。前面不是說漢字用兩個位元組嗎,那麼我們就將 10 放入第一個位元組中(高位位元組),01 放入第二個位元組中(低位位元組)——不對啊!這兩個值都小於 128 啊,按照前面的說法,表示漢字的兩個位元組的最高位必須是 1,轉成數值也即是必須大於 127 才對。另外我們前面用 python 程式碼打出來“啊”字的位元組值明明是 B0 A1 啊。

所以說這個區位碼僅僅是給人類看的,邏輯上的編號,它不等於計算機裡面的實際儲存表示。

區位碼在用計算機位元組表示的時候,肯定要做某種轉換——至少要讓它大於 127。區位碼本身都是小於 128 的(最大才 94),所以它們的位元組原碼的最高位都是 0,我們簡單地將最高位都變成 1 就行了——也就是在原來的值上加上 2^7 = 128 即可。

不過這樣得出來的值還不是最終的位元組編碼值,計算機中最終的位元組編碼值還要在此基礎上加上 32(至於為啥要加 32,大體原因是 GB 2312 想對 ASCII 中的可見字元重新進行了雙位元組的全形編碼,但這其中要排除掉那些不可列印的控制字元以及空格,所以要將原始區位碼後移 32 位。對詳細資訊感興趣的請自行百度)。也就是說,區位碼要加上 128 + 32 = 160(十六進位制 A0)才是機器位元組碼——為了和原始區位碼做區分,這個位元組碼有個新名字叫內碼

我們算下漢字“啊”的內碼。高位位元組:16 + 160 = 176,轉成十六進位制是 B0;低位位元組:01 + 160 = 161,轉成十六進位制是 A1,即“啊”字的內碼是 B0 A1,和前面 python 程式輸出的相吻合。

我們平時說某漢字的 GB 2312 編碼值一般就是指內碼。

img

三種碼值對照表。原始區位碼加 32 後的值也有個新名字叫“國標碼”

GBK:

1980 年的 GB 2312 只收錄了 6763 個漢字,雖然能滿足 99% 以上的使用場景,但對於一些生僻字(如一些人名、古文字)就沒辦法處理了。另外一個問題是,GB 2312 不支援繁體字。

所以 1995 年又制定了《漢字內碼擴充套件規範》(GBK,Guo Biao Kuozhan 的首字母,是對 GB 2312-1980 的擴充套件)。GBK 完全相容 GB 2312,同時收錄了 Big5 中的全部繁體字,以及 GB 2312 中沒有的其他漢字,共計 21003 個漢字。

GBK 也是雙位元組編碼。問題來了,GB 2312 中要求兩個位元組的最高位必須是 1,那最多也只能表示 2^14 = 16384 個字元——不夠用啊。所以 GBK 只要求漢字的第一個位元組(高位位元組)的最高位必須是 1,第二位(低位位元組)最高位可以是 0。

GB 18030:

隨著字符集編碼國際標準 ISO/IEC 10646 和 Unicode 的不斷髮展,越來越多的字元被納入其中,而 GBK 一共才 2萬多個字元(主要是漢字),有點趕不上時代了。

中國在 GBK 制定後的第五年(2000 年)又制定了新標準 GB 18030-2000,用來替代 GBK 標準。GB 18030-2000 是強制性標準(GBK 只是指導性的),也就是說在中國大陸銷售的軟體必須支援 GB 18030-2000 標準。

GB 18030 的目標是向 Unicode/UCS 對齊(而 GBK 只是 GB 2312 到 Unicode 對齊程式的一個過渡性標準),2000 版的 GB 18030 在GBK 基礎上增加了 CJK 統一漢字擴充 A 的漢字(CJK 是中日韓的縮寫),GB 18030-2005 在 GB 18030-2000 基礎上增加了 CJK 統一漢字擴充 B 的漢字,收入漢字 70000 餘個。另外 GB 18030-2005 還包含多種我國少數民族文字(如藏、蒙古、傣、彝、朝鮮、維吾爾文等)。

誠然,2 個位元組已經不夠用了。GB 18030包含三種長度的編碼:單位元組的 ASCII、雙位元組的 GBK(略帶擴充套件)、以及用於填補所有Unicode 碼位的四位元組 UTF 區塊。GB 18030 是完全相容 GBK 的,同時其碼點足以囊括所有的 Unicode 編碼空間。

注意 GB 18030-2005 是部分強制性的——其中囊括的 GB 18030-2000 部分是強制性的,在中國大陸銷售的相關軟體必須要支援該部分。


內碼表

我們知道,早期那些軟硬體製造商(IBM、微軟、蘋果等)在進入不同區域市場時,會單獨制定一套針對特定區域語言文字的字符集編碼標準,因而這些廠商內部都會持有很多套標準,這些字符集編碼標準在他們內部通過不同的編號來標識,並且起了個名字叫內碼表(Codepage,又稱內碼錶)。

每個廠商有自己的一套內碼表,這些內碼表僅供他們自己內部使用,雖然基本都相容 ASCII,但不同的內碼表之間(包括同一廠商內部以及廠商之間的)互不相容。比如 IBM 針對歐洲市場的 codepage 437(西尤拉丁字母)、852(東尤拉丁字母)、855(西裡爾字母) 等;微軟的 codepage 1251(西裡爾字母)、 1252(西尤拉丁字母)、1253(希臘字母)等。

後來,一些標準化組織(如 ISO、ANSI、中國國家標準局)和聯盟(如 Unicode 聯盟)參與制定了若干標準後,廠商們也將這些標準納入到自己的內碼表體系中。比如 GB 2312 在微軟內碼表編號是 936,Big5 是 950,UTF-8 是 65001,UTF-32 LE 是 12000,UTF-32 BE 是 12001。

我們發現,UTF-8、UTF-32 都是對 Unicode 字符集編碼標準的不同實現方式,在內碼表體系中分配了不同的編號(即UTF-8、UTF-32 LE、UTF-32 BE 屬於不同的內碼表)。也就是說,內碼表裡面的編碼是計算機的實際位元組碼,也就是字元在計算機中是怎麼用位元組表示的,這種編碼我們稱作“內碼”——這就是內碼表又稱為“內碼錶”的原因。

字元編碼有不同層次的表示,大體分為邏輯上(給人看的)和儲存上(給計算機看的)。比如我們前面提到的 GB 2312 的區位碼就屬於邏輯層面的編碼,而內碼則是儲存層面,如“啊”的區位碼是(十六進位制)10 01, 內碼是 B0 A1。“啊”字在微軟 codepage 936 的編碼就是 B0 A1。“啊”字的 Unicode 編碼是 U+554A,該(邏輯層面的)編碼用 UTF-8 和 UTF-32 表示出來是不一樣的,其 UTF-8 編碼是 E5 95 8A,UTF-32 BE 編碼是 00 00 55 4A,UTF-32 LE 編碼是 4A 55 00 00(BE 表示大端表示法,LE 是小端表示法)。

另外內碼表和一些標準之間不一定是完全等同的,往往是因某些標準滿足不了廠商的特定需求,廠商會在標準的基礎上做一些擴充套件,將標準納為內碼表的子集。比如微軟的 codepage 1252 對應 ISO/IEC 8859-1(latin 1),同時對其做了擴充套件。

另一方面,由於某些廠商的產品被廣泛使用,其制定的內碼表也就被其他廠商的產品支援。比如由於 IBM PC 在商業上的巨大成功,微軟的 MS-DOS 作業系統依賴其捆綁銷售,所以我們開啟微軟的內碼表列表可見裡面有大量的 IBM 內碼表,比如微軟的 codepage 437 就是對應的 IBM codepage 437,以及裡面很多有“OEM”描述的基本都是 IBM 的內碼表。具體參見:https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers。

image-20220217142617405

微軟對 IBM 內碼表的支援(部分)

Windows 的 ANSI 編碼

你在 Windows 上儲存記事本檔案時,在編碼欄會發現有個叫 ANSI 的編碼方式:

img

ANSI 是美國國家標準學會(American National Standards Institute),它是一個組織機構,被微軟放在這裡作為編碼方式著實讓人摸不著頭腦。這要了解一下它的歷史。

在微軟開發 Windows 視窗作業系統時,美國國家標準學會 ANSI 正在制定針對西歐語言文字的 ASCII 擴充套件草案(該草案後來被 ISO/IEC 接受作為 ISO/IEC 8859-1 標準)。微軟當時基於該草案制定了一個內碼表 codepage 1252 用來編碼西歐字元(注意微軟是基於草案制定的內碼表,那時候 ISO/IEC 8859-1 還沒有對外發布。codepage 1252 是 ISO/IEC 8859-1 的超集)。微軟管這個內碼表叫“ANSI codepage”(微軟官網對 codepage 1252 的描述是“ANSI Latin 1; Western European (Windows)”)。

也就是說,微軟說的 ANSI 編碼最早就是特指其基於 ANSI Latin 1 草案制定的 codepage 1252 這個內碼表。

後來 Unicode 出現了,微軟的新版本 Windows 很快就支援了 Unicode(最開始是以 UTF-16 的形式,所以你在微軟的編碼選項裡面會看到一項“Unicode”編碼項,就是指 UTF-16 編碼)。為了和 Unicode 編碼相區分,在 Windows 95 以及後續版本中,“ANSI 編碼”的含義已經不再單指 codepage 1252 了,而是指所有的非 Unicode 編碼方案——也就是說它不再表示一個內碼表,而是表示一組內碼表,具體表示哪個取決於系統設定,比如簡體中文環境就表示 codepage 936(GB2312)。


傳統編碼的問題

我們上面討論的這些編碼標準(ASCII、ISO/IEC 8859 系列、GB 系列、Big5 以及各軟硬體廠商自己制定的標準)都存在兩個問題:

  1. 沒有哪個編碼標準能囊括全世界所有的字元,因而必須針對不同的文字元號制定不同的標準(如針對歐洲各語系的 ISO 8859 系列,針對簡體中文的 GB2312,針對繁體中文的 Big5,針對日語的 Shift JIS 等)。
  2. 這些數目繁雜的標準之間互不相容(比如同一個數字編號 1000 在 GB2312 和 Big5 裡面表示的字元是不同的),因而軟體對一段文字一旦用錯了編碼標準就會出現亂碼。

以上問題導致的結果是,一個軟體要想用在不同語言的市場,就得同時支援多種編碼方式,特別在早期,這些工作都是各自廠商自己在做,耗費了大量的人力財力,而且還要不停地更新各種編碼標準。另外,由於各廠商對同一個語系的字元采用了不同的編碼標準,同樣一個法語檔案,在軟體 A 中開啟正常,在軟體 B 中可能就是亂碼,雖然 A 和 B 都支援法語字元。

總之,在很長一段時間,技術人員一邊要不厭其煩地開發、更新、相容各種字符集編碼,另一方面又要受著各種亂碼問題的折磨。

直到 1987 年的某一天,這幫人中的幾個終於忍無可忍,湊到一起,決定開發一套能容納全世界所有字元的標準,一統天下。

在下一篇文章中,我們將聊聊這個能“一統天下”的新編碼標準:Unicode。

原文連結:《字符集編碼(上):Unicode 之前》

相關文章