1. Введение
想像你是國際峰會上的外交官:每個人講自己的語言、用自己的書寫系統。要互相理解,需要一個通用的翻譯器——一套把符號對應起來的規則。在電腦裡,這個角色就是編碼。
電腦只懂一種「語言」——一連串的零和一。0 和 1 是它的「字母表」。所有資訊都是以位元組的形式儲存和傳輸。1 個位元組就是 8 個位元(比如 01000001)。
那要怎麼把我們的字母和符號和位元組連起來?電腦怎麼知道字母「A」不是單純的一串 0/1,而是在畫面上要顯示的那個符號?
Кодировка
編碼(кодировка)就是一套規則(對照表),決定每個符號(字母、數字、標點、漢字、emoji)怎麼被轉成位元組序列,然後那些位元組又怎麼被解讀回符號。
類比像莫爾斯電碼:你把文字轉成點和劃、傳送出去,接收者按同樣的規則還原符號。在電腦裡約定「位元組 ↔ 符號」的那套規則就是編碼。
2. Зачем же нам нужна эта головная боль с кодировками?
- 在人類和機器之間翻譯:沒有編碼,文本只是位元組;有了編碼,才是有意義的符號。
- 通用性與相容性:不同程式和作業系統得對規則達成共識。如果一個檔案宣告是 UTF-8,讀的時候也要用 UTF-8。
- 支援多種語言和符號:西里爾字母、阿拉伯書法、漢字、數學符號、emoji——可表示的符號越多,編碼就越複雜也越靈活。
3. ASCII – «первобытная» кодировка
最老牌、最基礎的編碼之一是 ASCII (American Standard Code for Information Interchange)。它用 7 位元來表示一個符號,也就是最多能表示 128 個不同的符號:拉丁字母 (A-Z, a-z)、數字 (0-9)、標點和控制碼(例如換行、製表)。
| 符號 | 十進位代碼 (ASCII) | 二進位代碼(7 位) |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 空格 | |
|
歷史上第 8 個位元常被用作 parity bit(奇偶校驗位),後來就被拿來在「擴充」ASCII 時使用——於是出現了針對不同區域的一位元組編碼,導致混亂。
如果你寫下「Hello」,在磁碟上大概就是這樣(每個符號 1 位元組;對 7-bit ASCII 來說最高位是 0):
H (01001000) e (01100101) l (01101100) l (01101100) o (01101111)
很簡單。但俄文字母或漢字在哪裡?在 ASCII 裡沒有——它是「單語言字典」,只適合基本的拉丁字元集合。
4. «Кракозябры» — почему кодировка это не шутки
有時打開檔案會看到類似 Привет 而不是「Привет」。這種現象叫做「亂碼」(或 Mojibake
比如,你把「Privet, mir!」(原文是俄文的「Привет, мир!」,這裡用拉丁轉寫)用 Windows-1251 存檔,對應到俄文字母的位元組可能像下面這樣(簡化表示):
- P → 207
- r → 240
- i → 232
- v → 226
- e → 229
- t → 242
然後你的同事用一個預期是 ISO-8859-1 (Latin-1) 的編輯器打開檔案,或你用 StreamReader 但沒指定編碼,而它跟檔案的編碼不一樣。結果:位元組 207 被用另一套表解讀——文字就壞掉了。
| 原始符號 (Windows-1251) | 位元組表示(示例) | 以 ISO-8859-1 解讀時的符號 |
|---|---|---|
| П | |
Ç |
| р | |
à |
| и | |
è |
| в | |
â |
| е | |
å |
| т | |
ò |
最後我們得到 Çàèâåò 而不是「Privet」。如果某個符號在預期的編碼裡根本不存在,你會看到方塊或問號。
實務上的主要結論:讀寫文字時要明確指定編碼,尤其是資料來源不是你控制的情況。在 .NET 裡可以透過在 StreamReader/StreamWriter 裡指定所需的 Encoding(例如 UTF-8 或 Encoding.GetEncoding("windows-1251"))。這樣可以避免亂碼,確保系統之間正確交換資料。
在接下來的課程裡,我們會學會如何在處理檔案和流時穩妥地選擇和指定編碼,讓你的程式更通用、國際化且可靠。
GO TO FULL VERSION