字符集和編碼

在計算機內部,全部信息都是由一串位來表示,表明的數據對象取決於它所處的上下文,多是數字、字符串或其餘。當爲字符串時,相信不少人遇到過亂碼問題,產生亂碼的根本緣由和字符集及其編碼有關。vue

  • 字符集(Character set):各類文字和符號的總稱,如ASCII字符集、Unicode字符集。
  • 字符編碼(Character encoding):指定位模式與字符符號的映射關係,如0x61表示字符'a'

ASCII

ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是英文字符的一種編碼方案。ASCII 字符集有兩類字符:控制字符和可打印字符。java

標準ASCII碼使用1字節(8-bit)中的 7 位表示,總共 2^7=128 種字符(0x00~0x7F),最高位爲0。其中前32個代碼和最後一個爲控制字符;0x20~0x7E 爲可打印字符,表明英文字母、數字、標點符號以及一些雜項符號,共95個。c++

ASCII碼已經可以知足現代英語的信息交換,但它們不能處理大部分歐洲國家的語言,由於他們還使用其餘拉丁字母的字符(如帶音標的),此外不一樣國家用到的字符也不一樣,爲了解決這個問題,ISO建立了ISO 2022標準,規範了7位和8位編碼的多個字符集中的字符,以及大字符集的表示,後來被應用於建立Latin-1,ISO 8859-1標準。markdown

ISO 8859

ISO 8859全稱爲ISO/IEC 8859,是一系列8-bit編碼字符集的標準,它經過擴展ASCII碼,利用 8-bit 中的第8位添加了另96個可打印字符的位置,其編碼區間是 0xA0~0xFF。ISO 8859定義了15個字符集,其中常見的是ISO 8859-1,西歐語言字符集app

這裏不得不提一下ISO-8859-1,它是IANA(互聯網號碼分配機構)根據ISO/IEC 8859-1標準制定的8-bit編碼字符集,別名latin1,編碼範圍是0x00~0xFF,各區間字符狀況以下:ui

  • 0x00~0x7F,依據ASCII字符集
  • 0x80~0x9F,ISO/IEC 2022中的C1控制字符
  • 0xA0~0xFF,依據ISO 8859-1,西歐語言字符集

ISO-8859-x系列編碼其實就是ISO 2022標準中各組件的特定組合。編碼

GB2312/GBK

單字節對於CJK字符來講顯然不夠用,ISO/IEC 2022標準在ISO 646標準(其前身就是ASCII)的基礎上,規範了大字符集的表示。7-bit編碼除了空格和33個控制字符外,總共能定義94個圖形字符,也就是說2個7-bit編碼可表示94x94個字符,三字節能表示更多。lua

GB2312就是我國根據ISO/IEC 2022標準,制定的簡體中文編碼標準字符集。GB2312中的字符就排列在94x94的方陣中,總共有8836個碼位,行稱爲區,列稱爲位,利用區號和位號能夠肯定一個字符,稱爲字符的區位碼(碼點),這裏的碼點使用的是十進制。url

  • 01-09,包括標點符號和其餘特殊字符
  • 16-55,一級漢字,按拼音排列。(3755個字符)
  • 56-87,二級漢字,按部首和筆畫排列。(3008個字符)

區 10-15 和 88-94 未分配。spa

GB2312字符集一般使用1字節或2字節的8位EUC-CN(一個多字節字符編碼)編碼,以便兼容ASCII碼,其餘漢字符號使用2-Byte表示。編碼規則:第一個字節稱高位字節,範圍是0xA1~0xF7(01-87區號加上0xA0);第二個字節稱低位字節,範圍是0xA1~0xFE(01-94位號加上0xA0)。好比「創」的碼點是2020(0x1414),那麼編碼就是0xB4B4。之因此要加上0xA0,我以爲是爲了區分ASCII編碼。

GBK是GB2312字符集的擴展,擴展了GB2312未分配的碼點,放棄了ISO 2022規定的控制字符塊,擴展了字節的範圍,第一個字節從A1~FE擴展到了81~FE(94+32=126),第二個字節40~FE(191),總共24,066個位置。

Unicode

Unicode 給每一個字符提供了一個惟一的數字,稱做碼點(code points),一般使用U+十六進制數來引用碼點,好比U+0041表示字符 ‘A’。Unicode 定義了1,114,112個碼點的代碼空間,範圍從 U+0000 到 U+10FFFF,代碼空間又分爲17個平面(0-16),每一個平面有65,536個碼點。其中0號平面叫作基本多語言平面(Basic Multilingual Plane, BMP),BMP範圍是U+0000~U+FFFF,使用4個hex數表示碼點。BMP以外的代碼點,使用5或6個hex數表示。

Unicode能夠經過不一樣的編碼方案來實現,最經常使用的是UTF-8UTF-16

UTF-16

UTF-16 以16-bit爲代碼單元(code units,2-Byte)對Unicode碼點編碼,BMP中的碼點編碼與UTF-16碼元相等,好比碼點U+2020,UTF-16編碼爲0x2020。其餘補充平面使用代理對(surrogate pairs),即兩個碼元表示一個碼點。

在BMP中,Unicode標準保留U+D800~U+DFFF這部分碼點用於高和低位代理的UTF-16編碼,其中U+D800~U+DBFF爲高位代理,U+DC00~U+DFFF爲低位代理。其餘補充平面編碼規則爲:

  • 碼點減去0x10000,保留0x000000..0x0FFFFF範圍內20位數
  • 用高10位bit加上0xD800給出第一個16位代碼單元或高位代碼
  • 用低10位bit加上0xDC00給出第二個16位代碼單元或低位代碼

計算機中大多以字節爲單位,那麼一個16位碼元的序列,就須要解決字節序的問題。UTF-16容許在實際編碼值以前加一個字節序標記 (Byte Order Mark ,BOM),值爲0xFEFF表示big-endian,值爲0xFFFE表示little-endian。Unicode 默認是 big-endian。

舉個例子,求碼點U+10393的編碼:

  • 0x10393-0x10000=0x393,那麼高10bit爲0x0,低10bit爲0x393
  • 則高位代碼爲0x0+0xD800=0xD800,低位代碼爲0x393+0xDC00=0xDF93
  • 按照大端序最終UTF-16的編碼爲FEFFD800DF93

UTF-8

UTF-8 是一種可變長度的編碼方案,以8-bit爲碼元,是互聯網普遍使用的一種Unicode實現方式,由於它字節少流量小。UTF-8使用1~4個字節對Unicode代碼空間中的有效碼點編碼。其編碼規則是,前128個字符(US-ASCII)使用一個字節編碼,與ASCII相對應;接下來1920個字符使用兩個字節編碼;BMP其他字符須要三個字節,其中包含了大多數中文;其餘平面中的字符使用四個字節。

下表是UTF-8編碼規則,其中x由碼點的位替換:

字節|碼位| 碼點範圍           | 編碼方式
----+-------------------------+---------------------------------------
  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

UTF-8使用8-bit代碼單元,避免了字節序的問題。求U+10393的UTF-8編碼:

  • 0x10393 > 0x10000據上表,使用4字節編碼
  • 將0x10393轉成二進制0001 0000 0011 1001 0011,從右到右依次替換編碼中的x
  • 替換結果爲11110000 10010000 10001110 10010011,即 F0908E93

FAQ

1. Unicode和UTF-8是什麼關係?

Unicode是字符集,而UTF-8是Unicode的一種編碼方案。

2. UTF-8的BOM?

這個是微軟的鍋,它給UTF-8加上的,通常仍是不要加BOM了。

3. 亂碼出現的緣由?

通常是使用了錯誤的字符集。避免亂碼的最好方法就是統一編碼(最好都是UTF-8),或者是知道字符的原始編碼方式。

相關文章
相關標籤/搜索