什麼是字元編碼
編碼是一種約定:「數字 65 代表字母 A」。當你寫一段文字時,程式會把這些數字存起來;別人打開它時,他們的程式會用同一個約定把這些數字轉回字母。如果雙方用的不是同一張表,文字就會顯示錯誤。
要區分兩個概念。一個是字元集,也就是哪些數字對應哪些符號的清單。另一個是這些數字如何以位元組存放。在 ASCII 中,兩者很簡單地一致;在 Unicode 中則不然,這時就輪到 UTF-8 登場。
ASCII:128 個 7 位元的字元
ASCII(American Standard Code for Information Interchange 的縮寫)在 1960 年代被制定為標準。它使用 7 位元,也就是 2 的 7 次方 = 128 個代碼,從 0 到 127。其中,33 個是控制字元(0 到 31 以及 127),95 個是可顯示字元(32 到 126,包含空格)。
它不包含帶重音符號的字母、ñ,或歐元符號:它是為英文設計的。這也說明了為什麼後來需要其他的代碼表。
| 控制字元 | 十進位 | 十六進位 | 二進位(7 位元) | 用途 |
|---|---|---|---|---|
| 空字元 (NUL) | 0 | 00 | 0000000 | 在許多語言中標示字串的結尾 |
| 水平定位 (TAB) | 9 | 09 | 0001001 | 跳到下一個定位點 |
| 換行 (LF) | 10 | 0A | 0001010 | 移到下一行 |
| 回車 (CR) | 13 | 0D | 0001101 | 回到該行的開頭 |
| 跳脫 (ESC) | 27 | 1B | 0011011 | 開始控制序列 |
| 空格 | 32 | 20 | 0100000 | 第一個可顯示字元 |
| 刪除 (DEL) | 127 | 7F | 1111111 | 刪除字元 |
值得記住的規律
這張表並不是隨機排列的。只要掌握幾個規律,你就能憑記憶讀出代碼。
- 數字「0」到「9」佔據 48 到 57(十六進位為 30 到 39)。一個數字的值就是它的代碼減去 48:「7」是 55,而 55 − 48 = 7。
- 大寫字母從 65(「A」)到 90(「Z」),小寫字母從 97(「a」)到 122(「z」)。
- 大寫字母和對應的小寫字母,差距永遠是 32:「A」= 65 而「a」= 97;「C」= 67 而「c」= 99。在二進位中只有一個位元不同:「A」是 01000001,「a」是 01100001。
- 要知道一個大寫字母在字母表中排第幾,減去 64:「C」是 67,而 67 − 64 = 3,也就是第三個字母。
- 因為所有大寫字母(65 到 90)的代碼都比小寫字母(97 到 122)小,所以「依代碼」的字母排序,會把「Zebra」排在「apple」前面。許多程式需要另外的比較選項,才能正確排序。
行尾:LF、CR 與 CRLF
換行看起來很簡單,但不同系統的寫法並不一樣。Unix、Linux 和 macOS 用單一字元 LF (10)。Windows 則連續用兩個,CR 和 LF(13 和 10),稱為 CRLF。舊式電傳打字機需要兩個不同的指令:把滑架移回開頭,並把紙往前推一行。
這個差異,正是為什麼檔案在基本編輯器裡會全部擠成一行,或是每一行結尾出現奇怪符號的原因。如果想知道它們各自是什麼代碼,在 ASCII 碼表的搜尋框輸入 LF 或 CR 即可。
「擴充 ASCII」並不是標準
因為一個位元組有 8 位元,而 ASCII 只用了 7 位元,所以有 128 個代碼空著(128 到 255),每個廠商和地區都用自己的方式填滿它們。這就是所謂的「擴充 ASCII」,但並沒有唯一的一張表:有很多張,稱為字碼頁。其中最有名的兩個是 Latin-1 (ISO-8859-1),其中 é 是代碼 233,以及 Windows-1252,兩者相似,但在 128 到 159 的代碼上有差異(例如歐元就在那裡)。
問題在於,代碼 233 在一張表中代表「é」,在另一張表中卻代表別的東西。用一張表寫、用另一張表讀的文字,就會顯示成亂碼。Unicode 的誕生,就是為了終結這種混亂。
Unicode 與 UTF-8
Unicode 為世界上幾乎所有書寫系統的每個字元,加上符號和表情符號,指派一個獨一無二的數字,稱為碼位。現在它有超過 150,000 個字元。寫法是加上前綴 U+,並用十六進位:「A」是 U+0041,「ñ」是 U+00F1,歐元是 U+20AC,笑臉表情符號是 U+1F600。前 128 個碼位和 ASCII 完全一樣。
UTF-8 是把這些數字存成位元組最常用的方式,依字元不同會用 1 到 4 個位元組。ASCII 的 128 個字元只佔一個位元組,和以前完全一樣,所以 ASCII 文字同時也是有效的 UTF-8 文字。其他字元則佔用更多位元組。
| 字元 | 碼位 | UTF-8 位元組數 | 位元組(十六進位) |
|---|---|---|---|
| A | U+0041 | 1 | 41 |
| é | U+00E9 | 2 | C3 A9 |
| ñ | U+00F1 | 2 | C3 B1 |
| € | U+20AC | 3 | E2 82 AC |
| 😀 | U+1F600 | 4 | F0 9F 98 80 |
為什麼會出現「ñ」而不是「ñ」
這是最常見的錯誤,而且有確切的原因。ñ 在 UTF-8 中是兩個位元組:C3 和 B1。如果程式以為這段文字是 Latin-1,就會把每個位元組當成一個字元來讀:C3 是「Ã」,B1 是「±」。結果就是「ñ」。「é」也一樣,會顯示成「é」,而「canción」則會顯示成「canción」。
解決辦法幾乎都是告訴程式,要以 UTF-8 開啟這個檔案(在文字編輯器中,或在試算表匯入的設定中)。反過來的情況,也就是 Latin-1 的文字被當成 UTF-8 讀取,通常會出現帶問號的菱形,因為那些單獨的位元組無法組成有效的 UTF-8 序列。
如何使用 ASCII 碼表與轉換功能
「ASCII 碼表」工具會顯示 128 個字元,以及它們的十進位、十六進位、八進位和二進位代碼,並附上控制字元的名稱。
- 在搜尋框輸入字元、代碼,或控制字元的名稱(例如 A、65、41 或 LF),找到它所在的那一列。
- 使用篩選按鈕(控制、數字、大寫、小寫、符號),只查看其中一組。
- 要轉換的話,在「文字」中輸入文字並選擇格式(十進位、十六進位、八進位或二進位):代碼會顯示在下方。「Hola」的十進位是 72 111 108 97,十六進位是 48 6F 6C 61。
- 也可以反過來做:把用空格或逗號分隔的代碼貼到「代碼」中,就會組成文字。十六進位接受 0x41 這類前綴。
如果文字中有不是 ASCII 的字元(例如 ñ),工具會提醒你,並顯示它的 Unicode 代碼。要看真正的 UTF-8 位元組,請使用「文字轉二進位」:ñ 是 11000011 10110001,兩個 8 位元的位元組。限制:碼表只顯示標準 ASCII,不含擴充的部分,而且一切都在你的瀏覽器中計算,不會把文字傳送到任何伺服器。
常見問題
ASCII 有多少個字元?
128 個,代碼從 0 到 127,每個 7 位元。其中 33 個是控制字元,95 個是可顯示字元(含空格)。
字母 A 和 a 的 ASCII 代碼是多少?
「A」是 65(十六進位 41,二進位 01000001),「a」是 97(十六進位 61,二進位 01100001)。兩者永遠相差 32。
ASCII 和 Unicode 有什麼差別?
ASCII 有 128 個為英文設計的字元。Unicode 有超過 150,000 個字元,涵蓋幾乎所有語言和表情符號,而它的前 128 個和 ASCII 相同。
什麼是 UTF-8?
它是把 Unicode 文字存成位元組最常用的方式。每個字元用 1 到 4 個位元組:ASCII 字元佔一個,ñ 佔兩個,表情符號佔四個。
為什麼我的文字顯示「ñ」或「é」?
因為以 UTF-8 儲存的文字,被當成 Latin-1 讀取了。以指定 UTF-8 編碼的方式重新開啟檔案,就能解決。