ASCII 的優雅:為何小寫字母不緊跟在大寫字母之後

當首次瀏覽 ASCII 表格時,會看到一個奇特的間隙。大寫 Z(十進位 90)之後,並未立即接上小寫 a(十進位 97)。相反地,出現了六個字符的序列:[, \, ], ^, _, 和 `。對於隨意的觀察者而言,這似乎是隨機的符號打斷了字母表。然而,這個間隙並非偶然;它是有意的設計選擇,簡化了電腦處理文字的方式。

二的次方

電腦以二進位資料運作,ASCII(美國資訊交換標準碼)的設計者針對當時的硬體對編碼進行了最佳化。理解 Za 之間間隙的關鍵在於數字 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') & 1101111101000001 ('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 的設計者確保常見的文字操作任務能以最高效率執行。

Sources