最後更新:2026年9月14日
第2週 語言、文本與編碼
1. 互動可視化與影片
- 字符編碼瀏覽器(Character Encoding Explorer):輸入任意文字,觀察它如何在 UTF-8、UTF-16、GB18030、Big5 等編碼之間變成一串字節,又如何還原。
- 字節對編碼訓練(Byte-Pair Encoding, BPE):逐步觀察 BPE 如何從字符或字節出發,合併高頻配對,學習出一套子詞詞表。
- 你懂乱码吗?锟斤拷烫烫烫(详解ASCII、Unicode、UTF-32、UTF-8编码)| Mojibake?(林粒粒呀,YouTube 影片):從亂碼現象出發,逐步解釋 ASCII、Unicode、UTF-32 與 UTF-8 的關係。
2. 什麼是「文本」?
對你來說,文本是字、句子、故事。對電腦來說,文本只是一串數字。電腦不會「看」中文或英文——它只認得兩種狀態:開與關,寫成 0 和 1。所有文字、標點、表情,都要先變成數字,才能儲存或傳送。讀回來時,必須用同一套規則;規則用錯,就會看到亂碼。這套規則叫編碼(encoding)。下面從最小的單位講起。
3. 比特:最小的開關
一個比特(bit,也作位元)就是一個只能是 0 或 1 的開關。比特愈多,能區分的東西就愈多——每多一個,選擇就翻一倍。
| 比特數 | 所有可能 | 一共幾種 |
|---|---|---|
| 1 | 0 1 | 2 |
| 2 | 00 01 10 11 | 4 |
| 3 | 000 001 010 011 100 101 110 111 | 8 |
規律很簡單:n 個比特 → 2n 種可能。8 個比特合稱一個字節(byte,也作位元組),共 256 種值(0–255)。檔案在硬碟裡、在網路上移動的,就是這些字節。
一長串 0 和 1 不好讀,所以也常寫成十六進位(hex):二進位每位只有 0 和 1,hex 每位有 0–9 和 A–F,共十六個符號。同一個數字,兩種寫法而已。
4. ASCII:先夠用英文
電腦最早要處理的是英文。工程師用 7 個比特(128 種)編了一張小表,叫 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼):英文字母、數字、常見標點,每個字符對應一個數字。美國標準協會在 1963 年公布第一版;1967 年的修訂補上小寫字母,大致就是今天仍在用的那 128 格。第八個比特補 0,所以每個 ASCII 字正好佔 1 個字節。下表三欄是同一個編號的三種寫法。
| 字符 | 十進位 | hex | 二進位 |
|---|---|---|---|
A | 65 | 41 | 01000001 |
a | 97 | 61 | 01100001 |
0 | 48 | 30 | 00110000 |
! | 33 | 21 | 00100001 |
128 格很快就滿了。中文、日文、表情都不在表裡——ASCII 從來沒打算裝下它們。後來各地各自發明編碼:中國大陸 1980 年公布 GB 2312,台灣資策會 1984 年訂出 Big5,1995 年的 GBK 再擴大大陸那一套。同一個檔案用錯規則打開,就變成亂碼。
5. Unicode:一張世界文字的大目錄
Unicode 的辦法是:做一張幾乎涵蓋全世界文字的大表,每個字符領一個獨一無二的編號。構想始於 1987 年 Xerox 與 Apple 的工程師(名稱由 Joe Becker 提出);Unicode 聯盟 1991 年成立,同年出版 Unicode 1.0。這個編號叫碼位(code point)。它只回答「這個字是幾號」,不規定這個號碼在檔案裡要怎麼存。
碼位習慣寫成 U+ 再加上一串 hex:
U+是標籤,意思是「這是 Unicode 編號」。- 後面的符號是 hex,跟二進位是同一個數的另一種寫法。
例如「A」的編號是十進位 65,hex 寫成 41,所以是 U+0041(前面多兩個 0,只是把位數寫齊)。「中」的編號是十進位 20013,hex 寫成 4E2D,所以是 U+4E2D。看到 U+4E2D,只要讀成:Unicode 表上,「中」的號碼是 4E2D。
6. UTF-8:把號碼存成字節
UTF-8 負責下一步:把碼位寫成字節,才能存檔或上網。1992 年 9 月,Ken Thompson 與 Rob Pike 為貝爾實驗室的 Plan 9 作業系統設計了它,讓舊的 ASCII 檔仍然合法;後來它成了網路的預設編碼。它是變長的——號碼小就少佔幾格,號碼大就多佔幾格。英文字母仍只佔 1 個字節(跟 ASCII 一模一樣),中文常佔 3 個,少數古字或表情佔 4 個。英文檔案因此維持小巧,又能裝下全球文字。
同一個字在不同編碼下會變成不同的字節。可用上面的字符編碼瀏覽器實際看這些差異。
電腦怎麼知道「這個字佔幾格」
UTF-8 在每個字節的開頭做記號:
- 這個字只佔 1 格:開頭是
0 - 佔 2 格:第一格開頭
110,後面那一格開頭10 - 佔 3 格:第一格開頭
1110,後面兩格開頭10 - 佔 4 格:第一格開頭
11110,後面三格開頭10
開頭的記號叫首字節與接續字節。記號佔掉的位子以外,剩下的 x 用來填碼位的二進位。
| 字節數 | 碼位範圍 | 開頭記號 | 例子(二進位) | 同一串(hex) |
|---|---|---|---|---|
| 1 | U+0000 – U+007F | 0xxxxxxx | A → 01000001 | 41 |
| 2 | U+0080 – U+07FF | 110xxxxx 10xxxxxx | é → 11000011 10101001 | C3 A9 |
| 3 | U+0800 – U+FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 中 → 11100100 10111000 10101101 | E4 B8 AD |
| 4 | U+10000 – U+10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 🚀 → 11110000 10011111 10011010 10000000 | F0 9F 9A 80 |
表裡的「碼位範圍」也是 U+ 加 hex:例如 U+0000–U+007F 就是編號 00 到 7F,正好是全部 ASCII。
以「中」走一遍。同一個編號,先寫十進位,再寫 hex,再拆成 3 個字節(每個 8 個比特):
- 十進位:20013
- hex:
4E2D(所以寫成U+4E2D) - 3 個字節:UTF-8 把這個號碼存成 8 + 8 + 8 個比特。3 字節的模板是
1110xxxx 10xxxxxx 10xxxxxx;把4E2D的二進位(0100 1110 0010 1101)填進x,得到:
| 8 個比特 | hex | |
|---|---|---|
| 第 1 字節 | 11100100 | E4 |
| 第 2 字節 | 10111000 | B8 |
| 第 3 字節 | 10101101 | AD |
粗體是開頭記號;橙色是從碼位填進去的比特。檔案裡實際存的,就是 E4 B8 AD。
兩個直接後果。第一,UTF-8 包含全部 ASCII:hex 00 到 7F 的寫法完全相同,舊的英文檔本身就是合法的 UTF-8。第二,每個字節的開頭都在說「我是一個字的開頭」還是「我接在後面」,所以即使從中間開始讀,也能找到字與字的界線。
7. 中文分詞
英文以空格分隔詞,電腦很容易切分;中文書寫時詞與詞之間沒有空格,例如「我喜歡吃火鍋」要切成「我/喜歡/吃/火鍋」才有意義。分詞(segmentation)就是把一串中文字切成一個個詞的過程。分詞工具不少,例如 spaCy、HanLP、THUNLP;本課用 jieba,它會根據詞典與統計機率來判斷切分位置。分詞結果會直接影響後續的詞頻、搭配、主題模型等所有分析,因此是中文文本處理的第一步。
注意:jieba 的詞典是為簡體中文訓練的,直接拿繁體文本去跑,切分品質會明顯變差。若你的文本是繁體(例如台灣、香港出版的小說),請先用 opencc 套件把文本轉換成簡體,再分句、再用 jieba 分詞。
8. 詞袋模型(Bag of Words, BoW)
把一篇文本看作一個「袋子」,只統計每個詞出現幾次,完全忽略詞的順序與語法。例如「貓追狗」和「狗追貓」在詞袋模型裡是一樣的:{貓:1, 狗:1, 追:1}。這個簡化看似粗糙,但對許多任務(如比較兩篇文章的主題、作者用詞差異)已經足夠,也是向量空間模型與主題模型的基礎。
9. 停用詞(stopwords)
停用詞指在文本中出現頻率極高、但對區分文本意義幫助不大的詞,例如中文的「的、了、是、在、我、你」、英文的 "the, is, of, a"。做詞頻或主題分析前,常會先把停用詞移除,以免它們蓋過真正有訊息量的詞。停用詞表並無通用標準,應依語料與研究問題調整——例如研究「我」的頻率變化時,「我」就不能當停用詞刪掉。
10. Zipf 定律
Zipf 定律:在一段夠長的文本中,把所有詞按出現次數由高到低排列,第 n 名的詞的頻率大約與 n 成反比——也就是說,排名第 1 的詞出現次數約是第 2 名的兩倍、第 3 名的三倍,依此類推。結果是少數幾個詞佔了大部分出現次數,而長長的「尾巴」裡有大量只出現一兩次的罕見詞。這解釋了為什麼停用詞會主導詞頻表,也說明文本資料為何高度不均。
11. 課堂練習
到 qhchina-data/corpora 選一本小說的 .txt,把下面提示裡的 [link] 換成檔案網址,再貼進 OpenCode:
提示
Please download this novel as a .txt file [link] Then write a .py script that: - uses jieba to segment the text into words, removing punctuation marks - prints the 10 most frequent words - saves a simple png bar chart of the 100 most frequent words (columns only, no labels or annotations) jieba and matplotlib are already installed; do not create a virtual environment.
完成後,看終端機印出的前 10 個詞,再開 .png。左邊幾根最高的柱,多半就是停用詞;整張圖由高到低迅速落下,就是 Zipf 定律。
若你用的是 Codespace,做完後請把結果 commit 並 push 到 GitHub。Codespace 被刪掉以後,沒有推上去的檔案就找不回來。