深入理解字符編碼

一、前言

字符編碼這個問題,困擾了無數(shù)程序員,一不小心就會掉進坑里,每當在開發(fā)中遇到亂碼或者emoji表情符的奇怪問題時總是讓人頭疼不已,本文就來從根源上研究一下字符編碼的本質(zhì)和原理。

二、何為編碼

編碼的本質(zhì)其實就是翻譯,舉個幾個??:

  1. 兩個說普通話的中國人進行交流時,是不需要編碼的,一個人說「你好」,另一個就能直接聽明白意思,反之亦然。
  2. 一個中國人和美國人交流時,就需要多一個中文到英文、和英文到中文的翻譯過程,才能實現(xiàn)雙向交流。
  3. 一個人類和計算機交流時,也是一樣的道理,大家都知道計算機只認識二進制0和1,因此必須把人類語言轉(zhuǎn)為二進制,才能把信息傳遞給計算機,這個過程叫做編碼(encoding),反之則稱為解碼(decoding)。

三、怎么編碼

1. ASCII

一種直觀的想法就是,制作一個映射表,把人類語言和計算機二進制對應(yīng)起來就行了,這樣的思想就孕育出了ASCII編碼(因為是美國人設(shè)計的,所以只有常用英文字符),如下表所示,非常直觀:


USASCII_code_chart

2. Unicode

但是ASCII表太小了,最多只能編碼128個字符,但人類語言又那么多,顯然無法滿足需求,于是世界各地的人們就分別設(shè)計了符合自己語言需求的映射表。在自己的地區(qū)使用時是沒有問題的,但是一旦進行國際交流,由于映射規(guī)則各不相同,就會導致混亂。

于是人們設(shè)計了一個很大的映射表——Unicode,總共可以編碼100多萬個字符(最多到 0x10FFFF),目的是為了容納世界上所有的人類語言。Unicode為每個字符分配了一個固定的數(shù)值,稱為編碼點(Code Point),這個值是全局唯一的。而且Unicode向前兼容 ASCII,原先在 ASCII 中定義的字符映射,在 Unicode 中也是一模一樣的。

3. UTF-8

按理說設(shè)計好了 Unicode,大家都按照 Code Point 編碼解碼,混亂的問題就已經(jīng)解決了,但是還有一個因素要考慮,就是存儲成本。

Unicode設(shè)計是三個字節(jié),如果不加考慮直接存儲 Code Point,那么所有的字符都需要占用三個字節(jié)。比如 'A',如果使用ASCII,則一個字節(jié)即可 0x41,如果使用 Unicode,則要編碼為 0x000041,這憑空多出來兩個字節(jié),對于英語文本來說完全是一個額外的存儲開銷。

為了降低存儲成本,人們發(fā)明了變長編碼,這里要注意下,并不是重新定義映射規(guī)則,還是用的 Unicode 的定義,只是以一種更加靈活的形式來存儲以節(jié)約空間。以目前通用性最高的 UTF-8 為例,原本只需要一個字節(jié)的 ASCII 字符,仍然只占一個字節(jié),而像中文及日語這樣的復雜字符就需要2個到3個字節(jié)來存儲。

UTF-8 的規(guī)則挺簡單的:

  • 對于單字節(jié)的符號,字節(jié)的第一位設(shè)為0,后面7位為這個符號的 Unicode 碼。因此對于英語字母,UTF-8 編碼和 ASCII 碼是相同的。
  • 對于n字節(jié)的符號(1 < n <= 4),第一個字節(jié)的前n位都設(shè)為1,第n + 1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒有提及的二進制位,全部為這個符號的 Unicode 碼。

維基百科的一覽表:

Number of bytes Bits for code point First code point Last code point Byte 1 Byte 2 Byte 3 Byte 4
1 7 U+0000 U+007F 0xxxxxxx
2 11 U+0080 U+07FF 110xxxxx 10xxxxxx
3 16 U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 21 U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

四、Emoji

??????……這些表情符大家應(yīng)該都已經(jīng)不陌生了,但它們并不是什么新的概念,其實也是 Unicode 的一部分,比如這個表情 ??的Code Point是:0x1F600,查上面的 UTF-8 編碼表可以看出需要4個字節(jié)來編碼:0xF09F9880。完整 emoji 列表可以參見這里:https://unicode.org/emoji/charts/full-emoji-list.html
。

MySQL emoji問題:
UTF-8 是能支持所有的 Unicode 字符的,因此按理說 emoji 不應(yīng)該會導致問題,但是在MySQL里實現(xiàn)的 utf8 最長只使用3個字節(jié),如果向一個編碼為 utf8 的列中插入一個表情符時,就會報類似Incorrect string value: '\xF0\x9F\xA6\x96 ...' for column 'name'
這樣的錯,可以看出此時想要插入的值已經(jīng)有四個字節(jié)了,因此需要指定該列編碼格式為 utf8mb4 才行。

五、參考資料

http://cenalulu.github.io/linux/character-encoding/
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
https://en.wikipedia.org/wiki/ASCII
https://en.wikipedia.org/wiki/Unicode
https://en.wikipedia.org/wiki/UTF-8

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

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

  • 大概每個人在使用軟件時都遇到過亂碼的問題,這是由于字符的編碼和解碼方式不一致導致,我們知道計算機只認識二進制數(shù)據(jù),...
    楚客閱讀 1,536評論 1 9
  • 字符是用戶可以讀寫的最小單位。計算機所能支持的字符組成的集合,就叫做字符集。字符集通常以二維表的形式存在。二維表的...
    劉惜有閱讀 8,366評論 2 14
  • 最近在開發(fā)中遇到了點Emoji相關(guān)的問題,便去了解了一下Emoji的編碼規(guī)則,發(fā)現(xiàn)其中涉及了許多字符集與字符集編碼...
    黎清海閱讀 10,924評論 3 15
  • 1. ASCII ??我們知道,計算機內(nèi)部是通過二進制數(shù)據(jù)進行操作的,所有的信息最終都會轉(zhuǎn)換為一個二進制值,二進制...
    騎著烏龜去看海閱讀 1,851評論 0 4
  • 想必大家都讀過西游記,應(yīng)該都對孫悟空這個人物并不陌生,他是吳承恩筆下塑造的最成功的人,敢愛敢恨,性格鮮明,天真爛漫...
    東閣堂主閱讀 509評論 0 0

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