一文讀懂字元編碼ASCII、Unicode與UTF-8

2023-03-13 21:01:38

先說一下,為什麼寫這篇文章?
最近在寫一個Http協定棧當涉及CRLF控制字元寫入時,發現自己對CRLF\r\n的關係不太瞭解,因此決定詳細學習一下;查閱資料的同時,又遇到UTF-8ASCII編碼的疑問。

一、ASCII 編碼

ASCII (American Standard Code for Information Interchange 美國資訊交換標準程式碼) 由128個字元構成,是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語,其對應的國際標準為 ISO/IEC 646

ASCII 由電報碼發展而來,第一版標準釋出於1963年,最後一次更新則是在1986年,至今為止共128個字元

  • 其中33個字元為不可顯示的控制字元,主要用於控制裝置或調整文字格式;
  • 在33個字元之外是95個可顯示字元
    包含26個英文大小寫字母10個阿拉伯數位以及包含空格在內的33個標點與特殊符號

1.1 EASCII

EASCII(Extended ASCII)是ASCII碼的擴充套件版本,其將ASCII碼由7位擴充為8位元,由128個字元擴充套件為256個字元,因此EASCII可以部分支援西歐語言。

1.2 跳脫字元

ASCII碼錶中的跳脫字元是一種約定寫法,是以反斜槓\開頭的特殊字元序列,作用是告訴計算機如何顯示與輸入控制字元。

跳脫字元的由來可以追溯到電傳打字機和電傳打字裝置的使用。
在這些裝置中,許多字元都是由多個部分組成的,需要多次按鍵才能輸入。例如,換行符通常需要按下確認鍵和換行鍵,而退格符需要按下後退鍵。為了簡化這個過程,制定了一些簡化輸入這些字元的規則,這些規則最終成為了ASCII跳脫字元的標準。

跳脫字元並非ASCII控制字元的某種編碼方式,而是一種約定俗成的寫法。當向計算機輸入跳脫字元時(如\r\n),其將自動將轉移字元替換為CRLF控制字元。
以下使用Java語言編寫了一個測試程式,當計算機遇到\r\n時,計算機自動將其替換為了CRLF控制字元,每個控制字元佔一個位元組

二、Unicode 編碼

Unicode (The Unicode Standard) 譯作萬國碼、統一字元碼、統一字元編碼,是資訊科技領域的業界標準,其整理、編碼了世界上大部分的文字系統,使得電腦能以統一字元集來處理和顯示文字,不但減輕在不同編碼系統間切換和轉換的困擾,更提供了一種跨平臺的亂碼問題解決方案。

Unicode由非營利機構Unicode聯盟(Unicode Consortium)維護,該機構致力讓Unicode標準取代既有的字元編碼方案,因為既有方案編碼空間有限,不適用於多語環境。Unicode伴隨著通用字元集ISO/IEC 10646的標準而發展,同時也以書本的形式對外發表。Unicode至今仍在不斷增修,每個新版本都加入更多新的字元,目前最新的版本為2022年9月公佈的15.0.0,已經收錄超過14萬個字元

Unicode 編碼是一個二進位制字元集,其字元佔用2~3個位元組。目前分為17個組進行編排,每個組稱為一個平面,每個平面擁有65536個編碼點,且當前只使用了少數平面。
因此,Unicode有足夠的編碼空間,可以將世界上所有的符號都納入其中,每一個符號都給予一個獨一無二的編碼,是名副其實的萬國碼。

三、UTF-8 編碼

UTF-8的英文全稱是(8-bit Unicode Transformation Format),其為 Unicode 的實現方式之一,也是目前網際網路上使用最廣的一種 Unicode 編碼的實現方式。

為什麼UTF-8成為網際網路使用最廣泛的一種編碼方式?

前邊說過Unicode 編碼是一個二進位制字元集,其只規定了字元的二進位制程式碼,卻沒有規定這些二進位制程式碼應該如何儲存。

比如:

  • 大寫英文字母A,其對應的ASCII二進位制編碼為8位元 ( 01000001 ),也就是說表示ASCII字元需1個位元組 ;
  • 漢字的 Unicode 十六進位制標識為590F,二進位制表示有16位元(0101100100001111),也就是說採用Unicode表示這個字元至少需要2個位元組;
  • 而對於Unicode編碼第14~16平面的字元,可能需要3個位元組表示。

因此,在計算機中如何進行Unicode編碼的儲存,出現了以下兩個問題:

  • 若所有的字元均按3個位元組進行表示:由於計算機儲存空間有限,將造成不小的空間浪費;
  • 若按1~3位元組對所有字元進行表示:計算機該如何區分ASCII 與 Unicode(計算機如何知道是一個位元組表示一個字元,還是三個位元組表示一個字元)?

在這種情況下UTF-8應運而生,UTF-8 最大的特點是一種可變長的編碼方式,其使用1~4個位元組表示一個符號,根據不同的符號而變化位元組長度。

UTF-8 的編碼規則很簡單,只有二條:

  • 對於單位元組的符號,位元組的第一位設為0,後面7位為這個符號的 Unicode 碼。
    因此,對於英語字母UTF-8 編碼和 ASCII 碼是相同的。
  • 對於n位元組的符號(n > 1):
    第一個位元組的前n位都設為1,第n + 1位設為0
    後面位元組的前兩位一律設為10
    剩下的沒有提及的二進位制位,全部為這個符號的 Unicode 碼。

下表總結了編碼規則,字母x表示可用編碼的位:

Unicode符號範圍        |   UTF-8編碼方式
(十六進位制)             |  (二進位制)
----------------------+----------------------------------
0000 0000 ~ 0000 007F | 0xxxxxxx
0000 0080 ~ 0000 07FF | 110xxxxx 10xxxxxx
0000 0800 ~ 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 ~ 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8編碼為什麼最多佔用4個位元組?

前邊我們瞭解到 Unicode 編碼的17個平面,最多使用3個位元組可全部表示。但為什麼 UTF-8 編碼最多卻是要使用4個位元組呢?

這是由 UTF-8 編碼的編碼規則決定的,對於編碼點 U+10000 到 U+10FFFF 範圍內的字元,UTF-8 編碼使用了 4 個位元組來表示。

Unicode符號範圍        |   UTF-8編碼方式
(十六進位制)             |  (二進位制)
----------------------+----------------------------------
0001 0000 ~ 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中:

  • 前面的位元組以「11110」開始,用於標識使用了 4 個位元組來表示一個字元。
  • 後面的 3 個位元組的前兩個位元組以「10」開始,用於標識這是一個多位元組字元的後續位元組。

使用四個位元組的好處還在於,可以為未來的 Unicode 字元預留更多的編碼空間。這是因為,Unicode 是一個持續發展的標準,每年都有新的字元被新增到其中。如果所有的字元都只使用三個位元組表示,那麼當 Unicode 標準新增更多字元時,就會出現編碼空間不足的問題。因此,使用四個位元組來表示這些字元可以保證未來的字元也能夠被正確編碼。

參考

wikipedia ASCII:
https://zh.wikipedia.org/zh-hans/ASCII

wikipedia Unicode:
https://zh.wikipedia.org/zh-cn/Unicode

wikipedia Unicode字元平面對映:
https://zh.wikipedia.org/zh-hans/Unicode%E5%AD%97%E7%AC%A6%E5%B9%B3%E9%9D%A2%E6%98%A0%E5%B0%84

wikipedia UTF-8:
https://zh.wikipedia.org/wiki/UTF-8

ISO/IEC 646 ASCII:
http://www.kostis.net/charsets/iso646.irv.htm

ISO/IEC 10646 Unicode:
http://www.kostis.net/charsets/iso10646.htm

ascii-code:
https://www.ascii-code.com/

Unicode 編碼表:
http://www.chi2ko.com/tool/CJK.htm

ASCII Unicode 和 UTF-8:
https://blog.csdn.net/qq_38310578/article/details/78433726

= THE END =

文章首發於公眾號」CODING技術小館「,如果文章對您有幫助,歡迎關注我的公眾號。