從 ASCII 到 Unicode — 為字元編上號碼
回顧為字元編上號碼的第 1 階段的歷史。從 ASCII 的 128 個字元、日文字元集的百家爭鳴,到為世界上所有字元編上唯一號碼 U+XXXX 的 Unicode。
所有字元編碼的祖先 — ASCII 的 128 個字元
「為字元編上號碼」這個構想的原點,是 1960 年代誕生於美國的 ASCII(American Standard Code for Information Interchange)。ASCII 把英文大寫、英文小寫、數字、符號,以及換行等控制字元,分配到 7 個位元、也就是 0〜127 這 128 個號碼上。
如果只有英語圈,這樣就夠了。但世界上的字元數量,遠遠不是 128 個裝得下的。從這裡開始,圍繞「號碼編法」的漫長混亂就此展開。
小題 2-1 — 用數字讀 ASCII
實際用數字讀一讀作為所有字元編碼基石的 ASCII。
Q1. 關於 ASCII 的說明,正確的是哪一個?
ASCII 是把英數字、符號、控制字元(換行等)分配到 7 個位元、也就是 0〜127 這 128 個號碼上的規格。不是 256 個字元 — 第 8 個位元的用途成為各國競相搶佔的擴充空間,這也是編碼百家爭鳴的原因之一。ASCII 不包含日文,是比 Unicode 古老得多的 1960 年代規格。
Q2. 在 ASCII 中「A」的號碼是十六進位的 0x41。換算成十進位是多少?(十六進位第 2 位數的權重是 16:0x41 = 4 × 16 + 1)
0x41 = 4 × 16 + 1 = 65。「A = 65」是許多程式語言中都會出現的經典數值,接下來是 B = 66、C = 67。小寫「a」是 0x61 = 97,與大寫剛好相差 0x20(32)— 這種規律性也是 ASCII 設計的巧妙之處。
Q3. ASCII 裡連一個日文字元都沒有。之後的發展,正確的是哪一個?
日本以 JIS 規格制定了包含漢字的字元集,而把它變成位元組序列的方式,則有 Shift_JIS、EUC-JP、JIS 編碼(ISO-2022-JP)等多種方式並立。同樣的日文文件,位元組序列卻因製作環境而異 — 這種百家爭鳴正是日文亂碼問題的溫床,被跨機種的郵件亂碼困擾的時代持續了很久。
日文的百家爭鳴時代 — 同一份文件在位元組層面卻是兩回事
在日本,包含漢字的字元集(哪個漢字編上幾號)以 JIS 規格的形式被制定出來。然而,把那些號碼變成位元組序列的方式(編碼)卻出現了好幾種。個人電腦的世界是 Shift_JIS,UNIX 的世界是 EUC-JP,電子郵件則是 JIS 編碼(ISO-2022-JP)—— 每個環境各自流行不同的方式。
同樣一句日文的「こんにちは」,Shift_JIS 的檔案與 EUC-JP 的檔案,位元組序列完全是兩回事。請回想第 1 章的口訣 — 收到沒有標籤的位元組序列的一方,只能猜測讀法,猜錯就亂掉。編碼百家爭鳴時代的日文,是亂碼的常客。這個時代的主角 Shift_JIS 至今仍在服役,所以第 4 章會深入到它的結構。
Unicode — 為世界上所有字元,編上唯一的號碼
既然號碼表因語言、因環境而百家爭鳴,那乾脆把世界上所有字元收進一張表,一次編上唯一的號碼 — 這就是 Unicode 的構想。平假名、漢字、阿拉伯文字、表情符號,全都放在同一個號碼空間裡。這個號碼稱為碼位(code point),寫作 U+XXXX(XXXX 是十六進位數)。
U+ 後面的十六進位數,習慣之後就能當成普通的數字來讀。十六進位 1 位數是 0〜15,各位數的權重是 1、16、256、4096。0x3042 = 3 × 4096 + 4 × 16 + 2 = 12354 — 只有這個換算,請在小題裡親手算一次。
Unicode 決定的只到第 1 階段(號碼)。同一個 U+3042,會因第 2 階段的編碼而變成不同的位元組序列。「Unicode = UTF-8」並不成立 — 這是這張圖的要點。
Unicode 只管到「號碼」— 變成位元組的工作還留著
這裡正是第 1 章的兩階段觀點發揮作用的地方。Unicode 解決的只有第 1 階段(號碼編法的統一)。把號碼變成位元組序列的第 2 階段,仍然存在多種方式 — UTF-8、UTF-16、UTF-32。它們都是承載同一套 Unicode 號碼的不同編碼。
光說「支援 Unicode」,並無法確定檔案的位元組序列。實務上被問的永遠是「是 UTF-8 還是 UTF-16?帶不帶 BOM?」這個第 2 階段的選擇。下一章我們就來處理它的代表 UTF-8,實際把位元填進去、親手組出來。
小題 2-2 — Unicode 與碼位
確認 Unicode「為世界上所有字元編上唯一號碼」的構想,以及 U+XXXX 表示法的讀法。
Q4. Unicode 的基本構想,正確的是哪一個?
從各語言號碼表百家爭鳴的教訓出發,Unicode 選擇了「把世界上所有字元收進一張表,編上唯一號碼」的道路。平假名、漢字、表情符號,都放在同一個號碼空間裡。「固定 2 個位元組」是早期的預估,如今碼位一路編到 U+10FFFF,2 個位元組已經裝不下 — 這件事會連到第 5 章的代理對。
Q5. 日文字元「あ」的碼位是 U+3042。U+ 後面是十六進位表示。0x3042 換算成十進位是多少?(3 × 4096 + 0 × 256 + 4 × 16 + 2)
十六進位 4 位數的權重是 4096、256、16、1,所以 3 × 4096 + 0 + 4 × 16 + 2 = 12288 + 64 + 2 = 12354。U+XXXX 這種表示法只不過是「用十六進位寫的號碼」,讀得懂它,Unicode 的文件就會親切許多。順帶一提,「あ」再往後兩個的 U+3044 是「い」(中間的 U+3043 是小寫的「ぃ」)。
Q6. 「U+3042」這個表示法指的是哪一個?
U+3042 是第 1 階段的「號碼」。要儲存它,必須經過第 2 階段的編碼把號碼變成位元組序列:UTF-8 是 E3 81 82,UTF-16 是 30 42。而不管選哪種編碼,號碼本身都不會變 — 這是關鍵。字型是為號碼賦予「形狀」的另一套機制,又是與編碼不同的另一層。
本章帶走的重點
- ASCII 是 7 位元、128 個字元。「A」= 0x41 = 65。是許多字元編碼的基石
- 日文經歷了 Shift_JIS、EUC-JP 等編碼百家爭鳴的漫長時代,是亂碼的溫床
- Unicode 為世界上所有字元編上唯一的號碼(碼位,U+XXXX)。「あ」= U+3042 = 12354
- Unicode 決定的只到號碼為止。變成位元組的第 2 階段(UTF-8 等)仍是另一個選擇
下一章終於輪到第 2 階段的主角 UTF-8。U+3042 變成 E3 81 82 的過程,由你自己親手計算。