UTF-8編碼

介紹 UTF-8 編碼

UTF-8 是一種針對 Unicode 的可變長度字符編碼。

針對 Unicode:UTF-8 是 Unicode 的實(shí)現(xiàn)方式之一。相當(dāng)于 Unicode 規(guī)定了字符對應(yīng)的代碼值,這個代碼值需要轉(zhuǎn)換為字節(jié)序列的形式,用于數(shù)據(jù)存儲、傳輸。代碼值到字節(jié)序列的轉(zhuǎn)換工作由 UTF-8 來完成。

可變長度字符編碼:UTF-8 使用一至四個字節(jié)對 Unicode 字符集中的所有有效代碼點(diǎn)進(jìn)行編碼。

  • UTF-8 使用 1 個字節(jié)表示 ASCII 字符;
  • UTF-8 使用 2 個字節(jié)表示帶有附加符號的拉丁文、希臘文等;
  • UTF-8 使用 3 個字節(jié)表示其他基本多文種平面(BMP)中的字符(包含了大部分常用字,如大部分的漢字);
  • UTF-8 使用 4 個字節(jié)表示 Unicode 輔助平面的字符。

技術(shù)是為了解決問題而生的,UTF-8 編碼是為了解決什么問題而設(shè)計(jì)的呢?UTF-8 是為了兼容 ASCII 編碼而設(shè)計(jì)的。

ASCII 編碼使用 1 個字節(jié)表示 ASCII 字符,而 Unicode 最初規(guī)定使用 2 個字節(jié)來表示所有的 Unicode 字符。如果使用 2 個字節(jié)來表示 ASCII 字符的話,那么含有大量 ASCII 字符的文本將浪費(fèi)大量的存儲空間。

UTF-8 編碼使用 1 個字節(jié)來表示 ASCII 字符,而且字面與 ASCII 碼的字面一一對應(yīng),這使得原來處理 ASCII 字符的軟件無須或只須做少部分修改,即可繼續(xù)使用。

UTF-8 編碼的規(guī)則

Unicode 和 UTF-8 之間的轉(zhuǎn)換關(guān)系表(x 字符表示碼點(diǎn)占據(jù)的位)

碼點(diǎn)的位數(shù) 碼點(diǎn)起值 碼點(diǎn)終值 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
7 U+0000 U+007F 1 0xxxxxxx
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
image-20230124102710527.png

UTF-8 編碼的規(guī)則:

  • 在 ASCII 碼范圍內(nèi)的代碼點(diǎn),UTF-8 使用 1 個字節(jié)表示。
  • 大于 ASCII 碼范圍的代碼點(diǎn),UTF-8 使用多個字節(jié)表示。UTF-8 使用第一個字節(jié)的前幾位表示該 Unicode 字符的字節(jié)長度(第一個字節(jié)的開頭 1 的數(shù)目就是該 Unicode 字符的字節(jié)長度),其余字節(jié)的前兩位固定為 10,作為標(biāo)記
    • 如果第一個字節(jié)的前<u>兩</u>位為 1,第三位為 0(110xxxxx),則表示 UTF-8 使用 2 個字節(jié)表示該 Unicode 字符;
    • 如果第一個字節(jié)的前<u>三</u>位為 1,第四位為 0(1110xxxx),則表示 UTF-8 使用 3 個字節(jié)表示該 Unicode 字符;
    • 依此類推;
    • 如果第一個字節(jié)的前<u>六</u>位為 1,第七位為 0(1111110x),則表示 UTF-8 使用 6 個字節(jié)表示該 Unicode 字符;

UTF-8 編碼的字節(jié)含義:對于 UTF-8 編碼中的任意字節(jié) B:

  • 如果 B 的第一位為 0(0xxxxxxx),則 B 獨(dú)立的表示一個 ASCII 字符;
  • 如果 B 的第一位為 1,第二位為 0(10xxxxxx),則 B 為一個多字節(jié)表示的字符中的一個字節(jié);
  • 如果 B 的前二 / 三 / 四 / 五 / 六位為 1,其余位為 0,則 B 為二 / 三 / 四 / 五 / 六個字節(jié)表示的字符中的第一個字節(jié)。

UTF-8 編碼示例

Unicode/UTF-8-character table (utf8-chartable.de)

image-20230124160453248.png

通過 UTF-8 編碼表,我們可以看到中文字符 “一” 的 Unicode 代碼點(diǎn)為 "U+4E00",UTF-8 編碼結(jié)果為 "e4 b8 80",

對中文字符 “一” 進(jìn)行 UTF-8 編碼,是如何得到 "e4 b8 80" 的呢?我們下面來看。


"4E00" 的二進(jìn)制表示為 "0100 1110 0000 0000"。

UTF-8 使用 3 個字節(jié)表示常用的漢字,因此中文字符對應(yīng)的字節(jié)序列格式為:"1110xxxx 10xxxxxx 10xxxxxx"

于是中文字符 “一” 的 UTF-8 編碼結(jié)果為 "1110<u>0100</u> 10<u>111000</u> 10<u>000000</u>",它的十六進(jìn)制表示為 "e4 b8 80"

public static void main(String[] args) throws UnsupportedEncodingException {
    byte[] bytes = "一".getBytes("UTF-8");
    // [-28, -72, -128]
    System.out.println(Arrays.toString(bytes));
}

UTF-8 編碼的優(yōu)劣局限

UTF-8 編碼的優(yōu)點(diǎn)

UTF-8 和 ASCII 兼容:ASCII 是 UTF-8 的一個子集。因?yàn)橐粋€純 ASCII 字符串也是一個合法的 UTF-8 字符串,所以現(xiàn)存的 ASCII 文本不需要轉(zhuǎn)換。為傳統(tǒng)的擴(kuò)展 ASCII 字符集設(shè)計(jì)的軟件通??梢圆唤?jīng)修改或很少修改就能與 UTF-8 一起使用。

任何面向字節(jié)的字符串搜索算法都可以用于 UTF-8 的數(shù)據(jù)(只要輸入僅由完整的 UTF-8 字符組成)。UTF-8 可以保證一個字符的字節(jié)序列不會包含在另一個字符的字節(jié)序列中。而有些比較舊的可變長度字符編碼(如Shift JIS)沒有這個特質(zhì),故它們的字符串搜索算法變得相當(dāng)復(fù)雜。

UTF-8 字符串可以由一個簡單的算法可靠地識別出來。由于 UTF-8 字節(jié)序列的設(shè)計(jì),如果一個疑似為字符串的序列被驗(yàn)證為 UTF-8 編碼,那么我們可以有把握地說它是 UTF-8 字符串。一個字符串在任何其它編碼中表現(xiàn)為合法的 UTF-8 的可能性很低,可能性隨著字符串長度的增長而減小。 舉例說明,字符值 C0、C1、F5 至 FF 從來沒有出現(xiàn)。為了更好的可靠性,可以使用正則表達(dá)式來統(tǒng)計(jì)非法過長和替代值(可以查看W3 FAQ: Multilingual Forms上的驗(yàn)證 UTF-8 字符串的正則表達(dá)式)。

UTF-8 編碼可以通過屏蔽位 和 移位操作快速讀寫:屏蔽位是指將字節(jié)的高位置零,以便獲取低位的值;移位操作是指將字節(jié)的低位移動到高位,以便獲取高位的值。這樣,可以快速讀取和寫入 UTF-8 編碼的字符。

UTF-8 編碼的缺點(diǎn)

UTF-8 編碼不利于使用正則表達(dá)式進(jìn)行讀音檢索

正則表達(dá)式可以進(jìn)行很多高級的英文模糊檢索。比如,[a-h] 表示 a 到 h 間的所有字母。

同樣 GBK 編碼的中文也可以這樣利用正則表達(dá)式,比如在只知道一個字的讀音而不知道怎么寫的情況下,也可用正則表達(dá)式檢索,因?yàn)?GBK 編碼是按讀音排序的。雖然正則表達(dá)式檢索并未考慮中文的多音字,但是由于中文的多音字?jǐn)?shù)量不多,不少多音字還是同音不同調(diào)類型的多音字,所以大多數(shù)情況下正則表達(dá)式檢索是還可以接受的。

但是 Unicode 漢字不是按讀音排序的,它是按部首排序,所以不利于用正則表達(dá)式進(jìn)行讀音檢索。在只知道一個字的部首而不知道如何發(fā)音的情況下,UTF-8 可用正則表達(dá)式檢索而 GBK 不行。


UTF-8 的 ASCII 字符只占用一個字節(jié),比較節(jié)省空間,但是更多字符的 UTF-8 編碼占用的空間就要多出1/2,特別是中文、日文和韓文(CJK)這樣的方塊文字,它們大多需要三個字節(jié)。

無法根據(jù) Unicode 字符數(shù)判斷出 UTF-8 文本占用的字節(jié)數(shù)。因?yàn)?UTF-8 是一種可變長度字符編碼。

參考資料

UTF-8 - 維基百科,自由的百科全書 (wikipedia.org)

Unicode/UTF-8-character table (utf8-chartable.de)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容