ASCII 的優雅:為何小寫字母不緊跟在大寫字母之後
當首次瀏覽 ASCII 表格時,會看到一個奇特的間隙。大寫 Z(十進位 90)之後,並未立即接上小寫 a(十進位 97)。相反地,出現了六個字符的序列:[, \, ], ^, _, 和 `。對於隨意的觀察者而言,這似乎是隨機的符號打斷了字母表。然而,這個間隙並非偶然;它是有意的設計選擇,簡化了電腦處理文字的方式。
二的次方
電腦以二進位資料運作,ASCII(美國資訊交換標準碼)的設計者針對當時的硬體對編碼進行了最佳化。理解 Z 與 a 之間間隙的關鍵在於數字 32——一個二的次方($2^5$)。
英文字母共有 26 個字母。透過在大寫與小寫集合之間加入 6 個額外字符,設計者在任一大寫字母與其對應小寫字母之間創造了恰好 32 個碼位的距離。
比較二進位表示
如果我們觀察 'A' 與 'a' 的二進位表示,模式便顯而易見:
| 十進位 | 二進位 | 符號 |
|---|---|---|
| 65 | 01000001 |
A |
| 97 | 01100001 |
a |
| 66 | 01000010 |
B |
| 98 | 01100010 |
b |
| 67 | 01000011 |
C |
| 99 | 01100011 |
c |
在每一個例子中,大寫與小寫字母唯一的差異在於 第 5 位元(代表 $2^5$,即 32 的位元)。當第 5 位元為 0 時,字母為大寫;當第 5 位元為 1 時,字母為小寫。
位元運算的魔法:大小寫轉換
由於大小寫差異僅限於單一位元,開發者可以使用極速的位元運算來執行大小寫轉換,而不必依賴複雜的條件判斷或查找表。
轉換為大寫
若要強制將字符轉為大寫,可使用與 32 的位元 NOT 之位元 AND。這實際上會產生一個遮罩,將第 5 位元清除,同時保持其他位元不變。
步驟 1:建立遮罩
~ 00100000 (32) → 11011111
步驟 2:將遮罩套用於 'a'
01100001 ('a') & 11011111 → 01000001 ('A')
轉換為小寫
轉換為小寫更為簡單。透過使用與 32 的位元 OR,即可確保第 5 位元被設定為 1,無論它原本是否已為 1。
01000001 ('A') | 00100000 (32) → 01100001 ('a')
切換大小寫
如果需要翻轉字符的大小寫(大寫轉小寫或相反),使用與 32 的位元 XOR(異或)即可切換第 5 位元。
01100001 ('a') ^ 00100000 (32) → 01000001 ('A')
01000001 ('A') ^ 00100000 (32) → 01100001 ('a')
判斷字母順序位置
除了大小寫轉換之外,這種結構還提供了一種快速判斷字母在字母表中位置的方法(A 為 1,B 為 2,依此類推)。透過對 31(二進位 00011111)執行位元 AND,即可清除較高位元,只保留低五位元。
這在數學上等同於 character % 32,因為 32 是二的次方。
'A'(65) → $65 \pmod{32} = 1$'Z'(90) → $90 \pmod{32} = 26$'a'(97) → $97 \pmod{32} = 1$'z'(122) → $122 \pmod{32} = 26$
此設計反映了當時每個 CPU 時脈都極為寶貴的時代。透過將字母表與二進位邊界對齊,ASCII 的設計者確保常見的文字操作任務能以最高效率執行。