1. 程式人生 > >unicode、utf-8、ansi、gbk、gb2312編碼詳解

unicode、utf-8、ansi、gbk、gb2312編碼詳解

前言

作為一個開發人員或是測試人員,免不了要與各種各樣的編碼打交道,而且這些各種編碼總是讓人頭大,現在我們就來揭開他們的廬山真面目

移動還是聯通?

在開始本文前,我需要大家思考一個問題:你知道聯通為什麼幹不過移動嗎?
我們來看看微軟站在哪邊吧,用記事本寫下聯通兩個字:
這裡寫圖片描述
儲存後再從新開啟剛剛的檔案,你會發現微軟表態了:
這裡寫圖片描述
微軟的意思大概就是,聯通是啥玩意兒?同樣的方法,移動就沒毛病。想知道為什麼嗎?那就要仔細往下看了

ascii

很久以前,計算機制造商有自己的表示字元的方式。他們並不需要擔心如何和其它計算機交流,並提出了各自的 方式來將字形渲染到螢幕上。隨著計算機越來越流行,廠商之間的競爭更加激烈,在不同的計算機體系間轉換數 據變得十分痛苦,人們厭煩了這種自定義造成的混亂,於是就有人站出來阻止這種混亂,他振臂高呼,組織各大廠商開始統一編碼,與秦始皇統一文字與異曲同工之妙,他們用一個位元組來表示他們使用的字元,a,b,c,d什麼的,實際上他們只用了128個,其中0~31是控制字元,32~127是可顯示字元,這就是後來的ascii編碼了:
這裡寫圖片描述


但是啊,這些老美萬萬沒想到,計算機是如此的受人歡迎,很快計算機就在
其它國家流行開了,其它國家看有很多本土常用的字元,ascii中沒有,於是就有人想啊,一個位元組中不是才用了一半嗎,這不最高位還沒用嗎,於是各個國家就開始用最高位來擴充套件這個ascii以便能夠表示自己國家的一些字元,但是這並不是對每個國家都有效的,特別是我們的大天朝,你英文就那幾個,但是我們文化博大精深啊,我們的漢字那可就有好幾萬個,你就給我一個位元組,我怎麼玩?

gb2312、big-5與gbk

一個位元組要表示我國那麼多中文,是萬萬辦不到的,那麼就只好再加一個位元組了:
我們不客氣地把那些127號之後的奇異符號們直接取消掉, 規 定:一個小於127的字元的意義與原來相同,但兩個大於127的字元連在一起時,就表示一個漢字,前 面的一個位元組(他稱之為高位元組)從0xA1用到0xF7,後面一個位元組(低位元組)從0xA1到0xFE,這樣 我們就可以組合出大約7000多個簡體

漢字了。在這些編碼裡,我們還把數學符號、羅馬希臘的字母、 日文的假名們都編進去了,連在 ASCII 裡本來就有的數字、標點、字母都統統重新編了兩個位元組長的 編碼,這就是常說的”全形”字元,而原來在127號以下的那些就叫”半形”字元了。 中國人民看到這樣很不錯,於是就把這種漢字方案叫做 “GB2312”。GB2312 是對 ASCII 的中文擴 展。 但是,你以為這樣就夠用了嗎?當然不行,gb2312能夠表示很多簡體漢字,但是繁體怎麼辦呢?臺灣群眾很不滿啊,於是也自己搞了一套編碼,於是big-5誕生了,你以為這樣就完了?gb2312僅僅可以表示6000多個常用漢字你讓其它不常用的怎麼辦?於是擴充套件唄,把之前gb2312中沒有利用的位好好利用起來,就成了gbk,這又增加了20000多個漢字,但是咱們少數名族也要用電腦啊,於是有了後來的 GB18030

GB2312和GBK都是用兩個位元組來編碼的,就算用完所有的位(256*256=65536)也不夠為所有的漢字 編碼。於是就有了目前最新的GB18030,它採用類似UTF-8的編碼方式進行編碼(每個字元的編碼可以是 1、2或4個位元組),擁有上百萬個編碼空間,足以支援中日韓三國所有漢字,並且還可以支援國內少數民族 的文字。

但是這畢竟是屬於一種“方言”式的編碼,很多其它國家是不懂你這個編碼的,於是各種編碼的出現又導致了混亂,於是unicode閃亮登場了!

unicode與utf-8

在這之前我們需要先理清個概念:
Unicode只是簡單的字元到數字的一個對映,就相當於一個電話本,它是沒有位元組限制的,是可以無限表示的,它也不管一個字元在計算機中式怎麼儲存的,具體怎麼儲存涉及到字元編碼,而unicode應該叫做字符集
Unicode為世界上的每一個字元都弄了一個對應的數字,所以就不會再存在亂碼問題了,比如,漢字 嚴 的 Unicode 是十六進位制數 4E25 ,轉換成二進位制數足足有15位( 100111000100101 ),也就是說,這個符號的表示至少需要2個位元組。表示其他更大的符號, 可能需要3個位元組或者4個位元組,甚至更多,這裡會出現幾個問題:
A.我們怎麼知道是三個位元組一起表示一個字元,還是說三個位元組分別表示三個字元
B.之前一個ascii字元只需要一個位元組,但是現在用了unicode普遍使用三個或四個位元組,那使用英文就回浪費很多位元組
於是針對unicode出現了很多不通的編碼方案,這些方案就是為了解決unicode再計算機中具體怎麼儲存的問題,經常聽說的有:utf-8、utf-16、utf-32
utf-16是用兩個或四個位元組表示一個字元
utf-32使用四個位元組表示一個字元
而utf-8是可變長的編碼方案,它可以用1~4個位元組表示不同字元,顯而易見,前面兩種編碼方案會浪費很多位元組,而utf-8就很好了,所以我們現在也通常使用utf-8。
那utf-8具體是怎麼編碼unicode的呢?
1)對於單位元組的符號,位元組的第一位設為 0 ,後面7位為這個符號的 Unicode 碼。因此對於 英語字母,UTF-8 編碼和 ASCII 碼是相同的。
2)對於 n 位元組的符號( n > 1 ),第一個位元組的前 n 位都設為 1 ,第 n + 1 位設為 0 ,後面位元組的前兩位一律設為 10 。剩下的沒有提及的二進位制位,全部為這個符號的 Unicode 碼。
根據utf-8的編碼規則,我們就可以發現它很好的解決了前面的兩個問題:
相容ascii且不適用多餘的位元組,多位元組的字元,我們可以通過判斷它的第一個字元來確定位元組數。
這是一份編碼表,其中xxx處填寫相應的unicode值
這裡寫圖片描述
舉個例子:
“俠”的unicode表示是4fa0,根據上表我們來計算一下它的utf-8編碼:
根據上表,4fa0在第三行的位置,也就是我們需要把unicode值依次填入1110xxxx 10xxxxxx 10xxxxxx中,開始填字遊戲吧:
11100100 10111110 10100000
轉換為16進位制後:E4BEA0

ansi又是什麼?

其實ANSI並不是某一種特定的字元編碼,而是在不同的系統中,ANSI表示不同的編碼。你 的美國同事Bob的系統中ANSI編碼其實是ASCII編碼(ASCII編碼不能表示漢字,所以漢字為亂碼),而你 的系統中(“漢字”正常顯示)ANSI編碼其實是GBK編碼,而韓文系統中(“한국어”正常顯示)ANSI編碼其 實是EUC-KR編碼。
windows系統通過Windows code pages的值來確定當前系統的編碼方式。

現在我們就可以來看一下聯通幹不過移動的原因了,因為我們在記事本中不指定儲存編碼時預設時ansi,在中國的電腦上也就是gbk編碼,而聯通的gbk編碼是:
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
有沒有發現它和utf-8有點像?沒錯,它就是與utf-8編碼衝突了,在我們第二次開啟記事本的時候,記事本誤以為它是utf-8編碼。於是就按照utf-8的格式解析了,我們去掉模板後,再補上前導0:00000000 01101010
轉為16進位制:006A
對應unicode是小寫字元j
這裡寫圖片描述
但是後一個位元組用同樣的方法後是:0368不能表示任何字元,所以記事本機會亂碼了。

參考資料

ansi是什麼編碼:http://www.cnblogs.com/malecrab/p/5300486.html

阮一峰的解釋:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

中文字元的幾種編碼:http://www.cnblogs.com/malecrab/p/5300497.html

細說:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 :
http://www.cnblogs.com/malecrab/p/5300503.html

國外比較好的一篇文章(推薦):https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/

海納百川