理解字符編碼

寫代碼這麼久,忽然發現並不瞭解字符編碼。咱們天天寫下的代碼,或者文件,在計算機中到底是怎樣的存在?咱們都知道,計算機可以認識的只有 01。因此,不論任何數據,最終在計算機中只是 01 的排列組合。那麼計算機時如何識別這些排列組合的呢?這就須要 字符編碼(Character encoding)了。簡單的說,就是按照必定的規則將信息與其對應的 01 的排列組合對應起來,這樣計算機就能夠根據字符編碼識別出硬盤中的排列組合所表明的真實信息了。常見的 ASCII UTF-8 GBK 等等,都是典型的字符編碼。計算機究竟是如何辨別這些字符編碼的,就要看一下具體的字符編碼原理。html

ASCII

ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼),是基於拉丁字母的一套電腦編碼系統。注意最後兩個字母是 II,而不是羅馬數字 2。ASCII 是由美國國家標準協會制定的,標準的單字節字符編碼方案,用於基本文本的數據。起源於 50 年代後期,在 1967 年定案。它最初是美國國家標準,供不一樣計算機在相互通訊時用做共同遵照的西文字符編碼標準,它已被國際標準化組織定爲國際標準,稱爲 ISO 646 標準。適用於全部拉丁文字字母。segmentfault

標準 ASCII 碼使用單字符,即 8 個二進制位表示字符。第一位統必定爲 0,實際使用後面 7 位來表示,因此 ASCII 碼一共規定了 128 個字符的編碼,包括全部的大小寫字母,數字 0 到 9,標點符號以及一些特殊控制字符。windows

標準 ASCII 碼錶以下:微信

ASCII 是美國標準,並不能知足其餘語言的需求。例如英鎊符號,中文漢字等等。西方一些國家使用 8 個二進制位來表示字符,最多能夠表示 256 個字符。顯然,對於漢字而言,一個字符不可能知足需求。ui

ANSI

爲了擴充 ASCII 編碼,以用於顯示本國的語言,不一樣的國家和地區制定了不一樣的標準,由此產生了 GB2312 , BIG5 , JIS 等各自的編碼標準。這些使用 2 個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼,又稱爲 MBCS(Muilti-Bytes Charecter Set,多字節字符集)。在簡體中文系統下,ANSI 編碼表明 GB2312 編碼,在日文操做系統下,ANSI 編碼表明 JIS 編碼,因此在中文 windows下要轉碼成 gb2312 , gbk 只須要把文本保存爲 ANSI 編碼 便可。不一樣的 ANSI 編碼並不兼容,同一個二進制值在不一樣的編碼體系中可能表明不一樣的字,這就致使了 Unicode 的誕生。在介紹 Unicode 以前,簡單看一下 ANSI 中的中文編碼。編碼

GB2313

GB2312 也是 ANSI 編碼裏的一種,對 ANSI 編碼最初始的 ASCII 編碼進行擴充,爲了知足國內在計算機中使用漢字的須要,中國國家標準總局發佈了一系列的漢字字符集國家標準編碼,統稱爲 GB碼 ,或國標碼。其中最有影響的是於 1980 年發佈的《信息交換用漢字編碼字符集 基本集》,標準號爲 GB 2312-1980 ,因其使用很是廣泛,也常被通稱爲國標碼。GB2312 編碼通行於我國內地;新加坡等地也採用此編碼。幾乎全部的中文系統和國際化的軟件都支持 GB 2312操作系統

GB2312 是一個簡體中文字符集,由 6763 個經常使用漢字和 682 個全角的非漢字字符組成。其中漢字根據使用的頻率分爲兩級。一級漢字 3755 個,二級漢字 3008 個。code

GBK

GB2312 的出現,基本知足了漢字的計算機處理須要,可是對於人名,古漢語等方面的罕用字,GB2312 不能處理,這就致使了 GBK 的出現。orm

GBK 採用雙字節表示,整體編碼範圍爲 8140-FEFE ,首字節在 81-FE 之間,尾字節在 40-FE 之間,剔除 xx7F 一條線。總計 23940 個碼位,共收入 21886 個漢字和圖形符號,其中漢字(包括部首和構件)21003 個,圖形符號 883 個。cdn

Unicode

ANSI 編碼的缺點很明顯,同一個編碼值,在不一樣的編碼體系中表明着不一樣的字符,很容易形成亂碼。若是有一種編碼,將世界上全部的符號都融入其中,每一個符號都有對應的編碼值,這樣就不存在亂碼問題了。這就是 Unicode 編碼。

Unicode 編碼是一個很大的集合,如今的規模能夠容納 100 多萬個符號,每一個符號的編碼都不同。其實 Unicode 並非真正意義上的字符編碼,它只是一個字符集,規定了符號的二進制碼,卻沒有規定這個二進制碼應該如何存儲。Unicode 有一些具體的實現編碼,其中用途最普遍的莫屬 UTF-8

UTF-8

UTF-8 是使用最廣的 Unicode 的一種 Unicode 的實現方式 ,它是一種變長的編碼方式,使用 1 ~ 4 個字符表示一個符號,根據不一樣的符號而變化字符長度,提升了 Unicode 的編碼效率。先來看一下 UTF-8 對於不一樣字節數的符號的表示方法, x 表明可以使用的二進制位:

字節數 編碼規則 可表示字符數量
1 字節 0xxxxxxx 2的7次方 = 128
2 字節 11xxxxxx 10xxxxxx 2的11次方 = 2048
3 字節 1110xxxx 10xxxxxx 10xxxxxx 2的15次方 = 65536
4 字節 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 2的21次方 = 4194304

由上面的表很容易發現 UTF-8 的編碼規則:

  • 對於單字節符號,第一位爲 0,後面 7 爲表示這個符號的 Unicode碼。因此對於單字節符號,UTF-8 的表示方式與 ASCII 一致。

  • 對於 n 字節的符號,第一個字節的前 n 位都爲 1,第 n+1 位爲 0,後面的全部字節前兩位均爲 10,剩下的二進制位爲這個字符的 Unicode碼

使用這種變長編碼方式,對於單字節的符號僅需使用一個字節來表示,不會形成浪費。對於漢字來講,通常都是使用三個字符來表示。對於計算機來講,也很容易區分一個字符到底佔用幾個字節:

  • 若是一個字節的第一位爲 0,這個字節就是一個字符
  • 若是第一位爲 1,連續有多少個 1,就表示當前字符佔用多少個字節

除了 UTF-8,相應的還有 UTF-16。在 UTF-8 中,以 8 個二進制位表示一個字符,而在 UTF-16 中,以 16 個二進制位表示一個字符。16 個二進制位能夠直接表示 65536 個字符,因此在 UTF-16 中,漢字和英文字母具備一樣的地位,都是使用 16 個二進制位,即 2 個字節表示 1 個字符。對英文來講會形成浪費,可是對中文來講,能夠節省存儲空間。

關於字符編碼,應該有了一個大概的認識,在平常使用中,咱們要儘可能作到編碼的統一,避免出現亂碼的狀況。

參考文章:

文章同步更新於微信公衆號: 秉心說 , 專一 Java 、 Android 原創知識分享,LeetCode 題解,歡迎關注!