在計算機內部,全部信息都是由一串位來表示,表明的數據對象取決於它所處的上下文,多是數字、字符串或其餘。當爲字符串時,相信不少人遇到過亂碼問題,產生亂碼的根本緣由和字符集及其編碼有關。vue
0x61表示字符'a'
。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/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
ISO-8859-x系列編碼其實就是ISO 2022標準中各組件的特定組合。編碼
單字節對於CJK字符來講顯然不夠用,ISO/IEC 2022標準在ISO 646標準(其前身就是ASCII)的基礎上,規範了大字符集的表示。7-bit編碼除了空格和33個控制字符外,總共能定義94個圖形字符,也就是說2個7-bit編碼可表示94x94個字符,三字節能表示更多。lua
GB2312
就是我國根據ISO/IEC 2022標準,制定的簡體中文編碼標準字符集。GB2312中的字符就排列在94x94的方陣中,總共有8836個碼位,行稱爲區,列稱爲位,利用區號和位號能夠肯定一個字符,稱爲字符的區位碼(碼點),這裏的碼點使用的是十進制。url
區 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 給每一個字符提供了一個惟一的數字,稱做碼點(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-8
和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爲低位代理。其餘補充平面編碼規則爲:
計算機中大多以字節爲單位,那麼一個16位碼元的序列,就須要解決字節序的問題。UTF-16容許在實際編碼值以前加一個字節序標記 (Byte Order Mark ,BOM)
,值爲0xFEFF
表示big-endian
,值爲0xFFFE
表示little-endian
。Unicode 默認是 big-endian。
舉個例子,求碼點U+10393的編碼:
FEFFD800DF93
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編碼:
Unicode是字符集,而UTF-8是Unicode的一種編碼方案。
這個是微軟的鍋,它給UTF-8加上的,通常仍是不要加BOM了。
通常是使用了錯誤的字符集。避免亂碼的最好方法就是統一編碼(最好都是UTF-8),或者是知道字符的原始編碼方式。