---
# System prepended metadata

title: '"字元"其說: 終端(terminal)和字元編碼的前世今生'
tags: [System Software]

---

---
tags: System Software
---

# "字元"其說: 終端(terminal)和字元編碼的前世今生

:::warning
由於這些歷史小弟在下並未親身經歷，只是統整各方的資料。可能收集的資訊有錯，歡迎勘誤 :pray: 
:::

## 字元編碼

廣義來說，字元(character)是文字的基本單位，字元集(character set)則是指多個文字(可能是某種語言、數學符號等等)所形成的集合。由於電腦中的數據是由無數電晶體開關所建構成的，而這些開關只能有開/關兩種狀態，習慣上分別以 1 和 0 來表示，因此電腦內部可以看做是二進制數字的世界。為了方便文字在電腦中儲存和通過網路傳遞，我們需要統一的[字元編碼(Character encoding)](https://zh.wikipedia.org/zh-tw/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81) 標準將文字與二進位數字映射。



### Baudot code(ITA1)

要談到人類開始廣泛使用二進位編碼文字，以應用於儲存和通訊，可以追溯到印字電報機(printing telegraph)的發明。最著名的印字電報機最早是由法國人 Émile Baudot 所發明。其使用 [Baudot code](https://en.wikipedia.org/wiki/Baudot_code) 來交換信息，採用 5 個 bits 來進行編碼。Baudot 發明的電報裝置如下圖，發報方通過一個類似於鋼琴鍵盤樣的裝置輸入報文。該裝置上面有 5 個鍵，因此可以表示 $2^5 = 32$ 個狀態。然而，當時的需求除了希望能容下拉丁字母表的 26 個字母之外，還有 10 個數字與十幾個標點符號的輸入問題。Baudot 的解決辦法是使用兩套各自含 31 個元素的字元集，第一個字元集主要表示字母表，以及一個切換到第二個字元集的符號；第二個字元集表示 10 個阿拉伯數字及標點符號，以及一個切換到第一個字元集的符號；不共用切換符號。除了切換符號，又共用了兩個空白符號和兩個換行符號。這樣總共能表示 58 多個 Baudot code。收報方的機器自動解碼後，直接在紙帶上印出可供人直接閱讀的報文內容。Baudot code 也被稱作國際電報字母第 1 號（International Telegraph Alphabet No. 1，ITA1）。

![](https://i.imgur.com/4H6s3Zk.png)

:::info
沒錯 「印出在紙帶上」，所以我們會將顯示文字在終端(terminal)上稱為 `print` 並非毫無道理!
:::

### ITA2

在 1899 年，美國人 Donald Murray 發明了類似於標準打字機的電報輸入設備。這就是[電傳打字機(Teleprinter)](https://zh.wikipedia.org/zh-tw/%E9%9B%BB%E5%82%B3%E6%89%93%E5%AD%97%E6%A9%9F)。這使得只要是會用傳統打字機的普通人，就可以用接入電報網路的電傳打字機直接交流。電傳打字機通常由一個鍵盤、一台發送器、一台接收器及一台打印機組成。也有一些電傳打字機會付設打孔機及讀帶機，可以將訊息印製於[打孔帶(punched tape)](https://zh.wikipedia.org/zh-tw/%E6%89%93%E5%AD%94%E5%B8%B6) 上。或是用作讀帶機將已打孔的紙帶中的訊息讀取出來。編碼上還是採取了 Baudot 提出的 5 位元、雙字元集的辦法。但根據字符出現頻率而改進了編碼方案，使得高頻率字符只需要儘可能少的紙帶打孔，而低頻率字符就需要在紙帶上打孔較多。比方說 e 和 t 只需要打一個孔。這套編碼於 1930 年代被 CCITT 標準化為國際電報字母表第2號（the International Telegraph Alphabet No. 2，ITA2），一直使用到 1963 年被 7 位元的 ASCII 碼取代。

![](https://i.imgur.com/9HHSi45.png)

:::info
換句話說，打孔帶其實就相當於是過去電腦的「記憶體」! 打了孔的地方是 1，否則是 0，是不是和二進位的儲存方式一樣呢?
:::


### ASCII

在 1950 年代，電傳打字機開始連接到電腦上，而不是其他電傳打字機。由於 ITA2 是為機械設計的，它在位置下就顯得有些格格不入。於是為了電腦設計的 [ASCII](https://zh.wikipedia.org/zh-hant/ASCII) 出現了，它改為使用 7 bits 來表示文字。與電腦一起使用的電傳打字機被稱為終端(terminal，意涵為"連接的終點"、"終點站")，指的是讓用戶輸入數據至電腦，以及顯示結果的機器。而電傳打字機同時也被稱為 "TeleTYpewriter"，簡稱 TTY。沒錯! 在現代系統中你是否有印象看過像是 /dev/tty 的名稱? 即便現代的電腦已經不再使用電傳打字機作為輸入輸出的設備，terminal 和 tty 這樣的單字也被沿用至今。

> 延伸閱讀: [命令行界面 (CLI)、终端 (Terminal)、Shell、TTY，傻傻分不清楚？](https://segmentfault.com/a/1190000016129862)

:::info
人類過去真的是使用電傳打字機來寫程式的! 底下這張經典的圖片就是 Dennis Ritchie 和  Ken Thompson 使用 teletype 在 [PDP-11](https://zh.wikipedia.org/zh-tw/PDP-11) 上開發 UNIX 和 C。另外可以看看 [Altair 8800 - Video #7.1 - Loading 4K BASIC with a Teletype](https://youtu.be/qv5b1Xowxdk) 享受一下 ASMR (?)，[Programming the PDP11](https://www.youtube.com/watch?v=XV-7J5y1TQc) 這個可愛的小短片也展示了過去人類是如何在 [PDP-11](https://zh.wikipedia.org/zh-tw/PDP-11) 上寫程式。


![](https://i.imgur.com/YRALRjS.png)
:::

ASCII 中除了要編碼拉丁字母或阿拉伯數字等會顯示在終端上的字元，另外還要提供代表特定功能的[控制字元（control characters)](https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%AD%97%E7%AC%A6)。控制字元一般來說不具備可顯示的圖形，主要是作為與電腦端溝通的語言，例如可用來終止資料的傳輸、換行等等。

:::success
雖然沒有特別提起，ITA1/ITA2 中當然也存在控制字元!
:::


### Unicode

ASCII 的局限在於只能顯示 26 個基本拉丁字母、阿拉伯數字和英式標點符號，因此只能用於顯示現代美國英語，且處理 naïve、café、élite 這類外來語時，必須去除附加符號。於是 [EASCII](https://zh.wikipedia.org/wiki/EASCII) 從 ASCII 擴充出地 8 個 bits，加入包括表格符號、計算符號、希臘字母和特殊的拉丁符號。然而世界各地各有不同的文化發展，分別都創造自己的文字。比方說，數以萬計的漢字又該怎麼編碼呢? 定義自己國用的字元編碼算是一種辦法，像是在中國使用的 [GBK](https://zh.wikipedia.org/zh-tw/%E6%B1%89%E5%AD%97%E5%86%85%E7%A0%81%E6%89%A9%E5%B1%95%E8%A7%84%E8%8C%83)。在台灣這樣使用繁體中文的地區，我們則習慣用 [BIG5](https://zh.wikipedia.org/zh-tw/%E5%A4%A7%E4%BA%94%E7%A2%BC) (甚至還有[倚天 BIG5](https://zh.wikipedia.org/zh-tw/%E5%80%9A%E5%A4%A9%E4%B8%AD%E6%96%87%E7%B3%BB%E7%B5%B1)，聽起來有點意思吧(?))。不過，缺乏一致與系統性的編碼不僅讓資訊領域的從業人員頭痛，實際上不免也造成普通民眾的困擾。
> * [司法話題》網路判決書一堆「□」 司院斥資改善系統](https://news.ltn.com.tw/news/focus/paper/1194776)

為解決編碼系統紊亂的現象，[Unicode](https://zh.wikipedia.org/zh-tw/Unicode) (統一碼，又譯作萬國碼、統一字元碼、統一字符編碼) 終於被推出。其直至今日仍在更新，以支援各國的文字。它是資訊科技領域的業界標準，使得電腦能以一致的字元集來顯示文字。有了 Unicode 以後，我們終於不必為了顯示正確的信息而在編碼系統間切換了。可喜可賀!

## 小結

自此，我們簡單的帶各位讀者一窺終端和字元編碼一路至今的發展。

不過，Unicode 既然可以表示如此多樣的文字([emoji](https://unicode.org/emoji/charts/full-emoji-list.html) 就是由 Unicode 編碼的!)，自然也導致我們會在字元處理上衍生許多問題。Unicode 的編碼中可能存在許多你不知道的細節! 作為本世代的工程師自然不能置身事外，也得多多留意這些問題!

這裡列舉幾個問題:

* 考慮下段程式碼，這是否可以通過編譯?如果可以，這裡應該要印出多少呢?
```cpp
#include <stdio.h>
#include <string.h>

int main()
{
    char *family = "👪";
    char *handsomeguy = "林易緯";
    printf("%ld\n", strlen(family));
    printf("%ld\n", strlen(handsomeguy));

    return 0;
}
```

* 考慮下段程式碼，這是否可以通過編譯?如果可以，這裡應該要印出 YES 還是 NO?
```cpp
#include <stdio.h>
#include <string.h>

int main()
{
    char *c1 = "é";
    char *c2 = "é";
    
    if (strlen(c1) == strlen(c2)) {
        printf("YES\n");
    } else {
        printf("NO\n");
    }

    return 0;
}
```

或許有機會我們再聊聊這些有趣的知識吧~

## Reference

* [ASCII table and history](https://bestasciitable.com/)
* [認識中文字元碼](https://idv.sinica.edu.tw/bear/charcodes/Section01.htm)
* [西門子T100S電傳打字機](http://www.cmm.gov.mo/chi/exhibition/secondfloor/moreinfo/2_5_4_TTY_T100S.html)
* [Baudot code](https://en.wikipedia.org/wiki/Baudot_code)
* [電傳打字機(Teleprinter)](https://zh.wikipedia.org/zh-tw/%E9%9B%BB%E5%82%B3%E6%89%93%E5%AD%97%E6%A9%9F)
* [ASCII](https://zh.wikipedia.org/zh-hant/ASCII)
* [The TTY demystified](http://www.linusakesson.net/programming/tty/)
* [命令行界面 (CLI)、终端 (Terminal)、Shell、TTY，傻傻分不清楚？](https://segmentfault.com/a/1190000016129862)