C語言中文網 目錄
首頁 > 編程筆記 > C語言筆記 閱讀:2,794

字符編碼是怎么回事?

在計算機中我們所處理的字符信息,即文本信息(包括數字、字母、文字、標點符號等)是以一種特定編碼格式來定義的。為了使世界各國的文本信息能夠通用,就需要對字符編碼做標準化。

我們現在最常用也最基本的字符編碼系統是 ASCII 碼(American Standard Code for Information Interchange,美國信息交換標準碼)。ASCII 碼定義每個字符僅占一個字節,可表示阿拉伯數字 0~9、26 個大小寫英文字母,以及我們現在在標準鍵盤上能看到的所有標點符號、一些控制字符(比如換行、回車、換頁、振鈴等)。

ASCII 碼最高位是奇偶校驗位,用于通信校驗,所以真正有編碼意義的是低 7 個比特,因此只能用于表示 128 個字符(值從 0~127)。由于 ASCII 是美國國家標準,所以后來國際化標準組織將它進行國際標準化,定義為了 ISO/IEC 646 標準。兩者所定義的內容是等價的。

ISO/IEC 646 對于英文系國家而言是基本夠用了,但是對于拉丁語系、希臘等國家來說就不夠用了。所以后來 ISO 組織就把原先 ISO/IEC 646 所定義字符的最高位也用上了,這樣就又能增加 128 個不同的字符,發布了 ISO/IEC 8859 標準。

然而,歐洲大陸雖小,但國家卻有數百個,128 種擴展字符仍然不夠用。因此后來就在 8859 的基礎上,引入了 8859-n,n 從 1~16,每一種都支持了一定數量的不同的字母,這樣基本能滿足歐美國家的文字表示需求。

當然,有些國家之間仍然需要切換編碼格式,比如 ISO/IEC8859-1 的語言環境看 8859-2 的就可能顯示亂碼,所以,還得切換到 8859-2 的字符編碼格式下才能正常顯示。

而在中國大陸,我們自己也定義了一套用于顯示簡體中文的字符集——GB2312。它在 1981 年 5 月 1 日開始實施,是中國國家標準的簡體中文字符集,全稱為《信息交換用漢字編碼字符集·基本集》。

GB2312 收錄了 6763 個漢字,包括拉丁字母、希臘字母、日語假名、俄語和蒙古語用的西里爾字母在內的 682 個全角字符。

然后又出現了 GBK 字符集,GBK 1.0 收錄了 21886 個符號,其中漢字就包含了 21003 個。GBK 字符集主要擴展了繁體中文字。

由于像 GB2312 與 GBK 能表示成千上萬種字符,因此這已經遠超 1 個字節所能表示的范圍。它們所采用的是動態變長字節編碼,并且與 ASCII 碼兼容。
  • 如果表示 ASCII 碼部分,那么僅 1 個字節即可,并且該字節最高位為 0。
  • 如果要表示漢字等擴展字符,那么頭 1 個字節的最高位為 1,然后再增加一個字節(即用兩個字節)進行表示。

所以,理論上,除了第 1 個字節的最高位不能動之外,其余比特都能表示具體的字符信息,因而最多可表示27 + 215 = 32896種字符。

當然,正由于 GB2312 與 GBK 主要用于亞洲國家,所以當歐美國家的人看到這些字符信息時顯示的是亂碼,他們必須切換到相應的漢字編碼環境下看才能看到正確的文本信息。為了能真正將全球各國語言進行互換通信,出現了 Unicode(Universal Character Set,UCS)標準。它對應于編碼標準 ISO/IEC 10646。

Unicode 前后也出現了多個版本。早先的 UCS-2 采用固定的雙字節編碼方式,理論上可表示 216 = 65536 種字符,因此極大地涵蓋了各種語言的文字符號。

不過后來,標準委員會意識到,對于像希伯來字母、拉丁字母等壓根就不需要用兩個字節表示,而且定長的雙字節表示與原有的 ASCII 碼又不兼容,因此后來出現了現在用得更多的 UTF-8 編碼標準。

UTF-8 屬于變長的編碼方式,它最少可用 1 個字節表示 1 個字符,最多用 4 個字節表示 1 個字符,判別依據就是看第 1 個字節的最高位有多少個 1。
  • 如果第 1 個字節的最高位是 0,那么該字符用 1 個字節表示;
  • 最高 3 位是 110,那么用 2 個字節表示;
  • 最高 4 位是 1110,那么用 3 個字節表示;
  • 最高位是 11110,那么該字符由 4 個字節來表示。

所以 UTF-8 現在大量用于網絡通信的字符編碼格式,包括大多數網頁用的默認字符編碼也都是 UTF-8 編碼。

盡管 UTF-8 更為靈活,而且也與 ASCII 碼完全兼容,但不利于程序解析。所以現在很多編程語言的編譯器以及運行時庫用得更多的是 UTF-16 編碼來處理源代碼解析以及各類文本解析,它與之前的 UCS-2 編碼完全兼容,但也是變長編碼方式,可用雙字節或四字節來表示一個字符。

如果用雙字節表示 UTF-16 編碼的話,范圍從0x0000到0xD7FF,以及從0xE000到0xFFFF。這里留出0xD800到0xDFFF,不作為具體字符的編碼表示,而是用于四字節編碼時的編碼替換。當UTF-16表示0x10000到0x10FFFF之間的字符時,先將該范圍內的值減去0x10000,使得結果落在0x00000到0xFFFFF范圍內。然后將結果劃分為高10位與低10位兩組。將低10位的值與0xDC00相加,獲得低16位;高10位與0xD800相加,獲得高16位。比如,一個Unicode定義的碼點(code point)為0x10437的字符,用UTF-16編碼表示的步驟如下。

1)先將它減去0x10000——0x10437-0x10000=0x0437。

2)將該結果分為低10位與高10位,0x0437用20位二進制表示為00000000010000110111,因此高10位是0000000001=0x01;低10位則是0000110111,即0x037。

3)將高10位與0xD800相加,得到0xD801;將低10位與0xDC00相加,獲得0xDC37。因此最終UTF-16編碼為0xD801DC37。

我們看到,盡管UTF-16也是變長編碼表示,但是僅低16位就能表示很多字符符號,況且即便要表示更廣范圍的字符,也只是第二種四字節的表示方法,這遠比UTF-8四種不同的編碼方式要簡潔很多。因此,UTF-16用在很多編程語言運行時系統字符編碼的場合比較多。像現在的Java、Objective-C等編程語言環境內部系統所表示的字符都是UTF-16編碼方式。

另外,現在還有UTF-32編碼方式,這一開始也是Unicode標準搞出來的UCS-4標準,它與UCS-2一樣,是定長編碼方式,但每個字符用固定的4字節來表示。不過現在此格式用得很少,而且HTML5標準組織也公開聲明開發者應當盡量避免在頁面中使用UTF-32編碼格式,因為在HTML5規范中所描述的編碼偵測算法,故意不對它與UTF-16編碼做區分。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo