代碼單元與代碼點

代碼單元與代碼點

代碼點指編碼表(比如Unicode)中某個字符的代碼值(數字),書寫時前面加U+,比如U+0041是字母A的代碼點

java中的代碼單元指表示編碼表字符的最小存儲單元,用16位表示

Unicode 代碼點

U+0041

U+00DF

U+6771

U+10400

表示字形

       

UTF-32 代碼單元

00000041

000000DF

00006771

00010400

UTF-16 代碼單元

0041

00DF

6771

D801

DC00

UTF-8 代碼單元

41

C3

9F

E6

9D

B1

F0

90

90

80

增補字符,用兩個代碼單元表示的字符

 

網摘:

代碼點(Code Point)就是指Unicode中爲字符分配的編號,一個字符只佔一個代碼點,例如我們說到字符,它的代碼點是U+6C49.代碼單元(Code Unit)則是針對編碼方法而言,它指的是編碼方法中對一個字符編碼以後所佔的最小存儲單元。例如UTF-8中,代碼單元是一個字節,因爲一個字符可以被編碼爲1個,2個或者34個字節;在UTF-16中,代碼單元變成了兩個字節(就是一個char),因爲一個字符可以被編碼爲1個或2char(你找不到比一個char還小的UTF-16編碼的字符,嘿嘿)。說得再羅嗦一點,一個字符,僅僅對應一個代碼點,但卻可能有多個代碼單元(即可能被編碼爲2char)。

    以上概念絕非學術化的繞口令,這意味着當你想以一種統一的方式指定自己使用什麼字符的時候,使用代碼點(即你告訴你的程序,你要用Unicode中的第幾個字符)總是比使用代碼單元更好(因爲這樣做的話你還得區分情況,有時候提供一個16進制數字,有時候要提供兩個)。"

 

想找到第i個代碼點,使用下列語句

int index = greeting.offsetByCodePoints(0,i);  //得到0開始便宜i個代碼點的索引值(數字)

int cp = greeting.codePointAt(index);  // 返回char(unicode對應數字)

 

字符編碼

你是否認爲 ASCII 碼就是一個字符,一個字節就是一個字符,一個字符就是 8 比特?你是否認爲 UTF-8 就是用 8 比特表示一個字符?如果真的是這樣認爲這篇文章就很適合你。

爲什麼要有編碼?

首先大家需要明確的是在計算機裏所有的數據都是字節的形式存儲和處理的。我們需要字節來表示計算機裏的信息,但是這些字節本身又是沒有任何意義的。我們需要對這些字節賦予實際的意義,制定各種編碼標準。編碼模型

首先需要知道的是存在兩種編碼模型

簡單字符集

在這種編碼模型裏,一個字符集定義了這個字符集裏包含什麼字符,同時把每個字符如何對應成計算機裏的比特也進行了定義。例如 ASCII,在 ASCII 裏直接定義了 A -> 0100 0001

現代編碼模型

在現代編碼模型裏要知道一個字符如何映射成計算機裏比特,需要經過如下幾個步驟:

  1. 知道一個系統需要支持哪些字符,這些字符的集合被稱爲字符表(Character repertoire
  2. 給字符表裏的抽象字符編上一個數字,也就是字符集合到一個整數集合的映射。這種映射稱爲編碼字符集(CCS:Coded Character Set, unicode 是屬於這一層的概念,unicode 跟計算機裏的什麼進制啊沒有任何關係,它是完全數學的抽象的。
  3. CCS 裏字符對應的整數轉換成有限長度的比特值,便於以後計算機使用一定長度的二進制形式表示該整數。這個對應關係被稱爲字符編碼表(CEF:Character Encoding FormUTF-8, UTF-16 都屬於這層。
  4. 對於 CEF 得到的比特值具體如何在計算機中進行存儲,傳輸。因爲存在大端小端的問題,這就會跟具體的操作系統相關了。這種解決方案稱爲字符編碼方案(CES:Character Encoding Scheme)。

平常我們所說的編碼都在第三步的時候完成了,並沒有涉及到 CES。所以 CES 並不在本文的討論範圍之內。
現在也許有人會想爲什麼要有現代的編碼模型?爲什麼在現在的編碼模型要拆分出這麼多概念?直接像原始的編碼模型直接都規定好所有的信息不行嗎?這些問題在下文的編碼發展史中都會有所闡述編碼的發展史

ASCII

ASCII 出現在上個世紀 60 年代的美國,ASCII 一共定義了 128 個字符,使用了一個字節的 7 位。定義的這些字符包括英文字母 A-Za-z,數字 0-9,一些標點符號和控制符號。在 Shell 裏輸入man ASCII,可以看到完整的 ASCII 字符集。ASCII 採用的編碼模型是簡單字符集,它直接定義了一個字符的比特值表示。裏例如上文提到的A -> 0100 0001。也就是 ASCII 直接完成了現代編碼模型的前三步工作。
在英語系國家裏 ASCII 標準很完美。但是不要忘了世界上可有好幾千種語言,這些語言裏不僅只有這些符號啊。如果使用這些語言的人也想使用計算機,ASCII 就遠遠不夠了。所以到這裏編碼進入了混亂的時代。

混亂時代

人們知道計算機的一個字節是 8 位,可以表示 256 個字符。ASCII 卻只使用了 7 位,所以人們決定把剩餘的一位也利用起來。這時問題出現了,人們對於已經規定好的 128 個字符是沒有異議的,但是不同語系的人對於其他字符的需求是不一樣的,所以對於剩下的 128 個字符的擴展會千奇百怪。而且更加混亂的是,在亞洲的語言系統中有更多的字符,一個字節無論如何也滿足不了需求了。例如僅漢字就有 10 萬多個,一個字節的 256 表示方式怎麼能夠滿足呢。於是就又產生了各種多字節的表示一個字符方法(gbk 就是其中一種),這就使整個局面更加的混亂不堪。(希望看到這裏的你不再認爲一個字節就是一個字符,一個字符就是8比特)。每個語系都有自己特定的編碼頁(code pages)的狀況,使得不同的語言出現在同一臺計算機上,不同語系的人在網絡上進行交流都成了癡人說夢。這時 Unicode 出現了。

Unicode

Unicode 就是給計算機中所有的字符各自分配一個代號。Unicode 通俗來說是什麼呢?就是現在實現共產主義了,各國人民不在需要自己特定的國家身份證,而是給每人一張全世界通用的身份證。Unicode 是屬於編碼字符集(CCS)的範圍。Unicode 所做的事情就是將我們需要表示的字符表中的每個字符映射成一個數字,這個數字被稱爲相應字符的碼點(code point)。例如字在 Unicode 中對應的碼點是 U+0x4E25

到目前爲止,我們只是找到了一堆字符和數字之間的映射關係而已,只到了CCS的層次。這些數字如何在計算機和網絡中存儲和展示還沒有提到。

字符編碼

前面還都屬於字符集的概念,現在終於到 CEF 的層次了。爲了便於計算的存儲和處理,現在我們要把哪些純數學數字對應成有限長度的比特值了。最直觀的設計當然是一個字符的碼點是什麼數字,我們就把這個數字轉換成相應的二進制表示,例如 Unicode 中對應的數字是 0x4E25,他的二進制是100 1110 0010 0101,也就是嚴這個字需要兩個字節進行存儲。按照這種方法大部分漢字都可以用兩個字節來表示了。但是還有其他語系的存在,沒準兒他們所使用的字符用這種方法轉換就需要 4 個字節。這樣問題又來了到底該使用幾個字節表示一個字符呢?如果規定兩個字節,有的字符會表示不出來,如果規定較多的字節表示一個字符,很多人又不答應,因爲本來有些語言的字符兩個字節處理就可以了,憑什麼用更多的字節表示,多麼浪費。

這時就會想可不可以用變長的字節來存儲一個字符呢?如果使用了變長的字節表示一個字符,那就必須要知道是幾個字節表示了一個字符,要不然計算機可沒那麼聰明。下面介紹一下最常用的 UTF-8UTF Unicode Transformation Format的縮寫)的設計。請看下圖(來自阮一峯的博客)

x 表示可用的位

 

通過 UTF-8 的對應關係可以把每個字符在Unicode 中對應的碼點,轉換成相應的計算機的二進制表示。可以發現按照 UTF-8 進行轉換是完全兼容原先的 ASCII 的;而且在多字節表示一個字符時,開頭有幾個 1 就表示這個字符按照 UTF-8 轉換後由幾個字節表示。下面一個實例子來自阮一峯的博客

已知unicode4E25100111000100101),根據上表,可以發現4E25處在第三行的範圍內(0000 0800-0000 FFFF),因此UTF-8編碼需要三個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然後,從的最後一個二進制位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進制就是0xE4B8A5

除了 UTF-8 這種轉換方法,還存在 UTF-16UTF-32 等等轉換方法。這裏就不再多做介紹。(注意UTF後邊的數字代表的是碼元的大小。碼元(Code Unit)是指一個已編碼的文本中具有最短的比特組合的單元。對於 UTF-8 來說,碼元是 8 比特長;對於 UTF-16 來說,碼元是 16 比特長。換一種說法就是 UTF-8 的是以一個字節爲最小單位的,UTF-16 是以兩個字節爲最小單位的。)

 

代碼點(Code Point)Unicode是屬於編碼字符集(CCS)的範圍。Unicode所做的事情就是將我們需要表示的字符表中的每個字符映射成一個數字,這個數字被稱爲相應字符的碼點(code point)。例如“嚴”字在Unicode中對應的碼點是U+0x4E25

    代碼點是字符集被編碼後出現的概念。字符集(Code Set)是一個集合,集合中的元素就是字符,比如ASCII字符集,其中的字符就是'A''B'等字符。爲了在計算機中處理字符集,必須把字符集數字化,就是給字符集中的每一個字符一個編號,計算機程序中要用字符,直接用這個編號就可以了。於是就出現了編碼後的字符集,叫做編碼字符集(Coded Code Set)。編碼字符集中每一個字符都和一個編號對應。那麼這個編號就是代碼點(Code Point)。

 

代碼單元(Code Unit):是指一個已編碼的文本中具有最短的比特組合的單元。對於UTF-8來說,碼元是8比特長;對於UTF-16來說,碼元是16比特長。換一種說法就是UTF-8的是以一個字節爲最小單位的,UTF-16是以兩個字節爲最小單位的。

    代碼單元是把代碼點存放到計算機後出現的概念。一個字符集,比如有10個字符,每一個字符從09依次編碼。那麼代碼點就是01、。。。、9。爲了在計算機中存儲這10個代代碼點,一個代碼點給一個字節,那麼這裏的一個字節就是一個代碼單元。比如Unicode是一個編碼字符集,其中有65536個字符,代碼點依次爲012、。。。、65535,爲了在計算機中表示這些代碼點就出現了代碼單元,65536個代碼點爲了統一表示每個代碼點必須要有兩個字節表示才行。但是爲了節省空間0-127ASCII碼就可以不用兩個字節來表示,只需要一個字節,於是不同的表示方案就形成了不同的編碼方案,比如utf-8utf-16等。對utf-8而言代碼單元就是一個字節,對utf-16而言代碼單元就是兩個字節。

 

 

發佈了36 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章