計算機字符編碼詳解與匯總
前言
計算機中的數據是以二進製格式表示的(其中8位二進製稱為一個字節,比如00100101就是一個字節。通常為了更方便的表示二進製數據,也可以轉換成16進製表示出來,比如00100101就可以用0x25來表示)。把所有字符轉換成二進製數據的規則就是字符編碼。字符編碼的方式很多,本文對每一種字符編碼做盡可能詳細的講解。
本文中紅色字體或加粗字體是需要重點理解或者記憶的。
1. ASCII碼
ASCII是美國國家標準定製的一套基於拉丁字母的電腦編碼係統,可表示數字、字母等字符符號。
一個ASCII碼在計算機中由一個字節存儲,因此它最多可表示256個符號(一個字節為8位,2的8次方等於256),實事上,標準的ASCII編碼時隻用到了低7位(最高位統一為0,或者為奇偶校驗位),故ASCII碼可表示的數據一共隻有128個(2的7次方)。這128個字符中,其中95個為可顯示字符(可打印字符,比如數字、字母、標點符號),還有33個如比如“換行”之類的控製字符(控製字符主要是用來操控已經處理過的文字)。
對於ASCII具體哪個編碼表示哪個符號,大家可以去查閱ASCII編碼碼表,並具最好能記住數字符、字母、回車換行等常用字符對應的ASCII編碼,至少記住它的十進製編碼。
常用字符對應的ASCII編碼:
回車,ASCII碼13(十進製,下同)
換行,ASCII碼10
空格,ASCII碼32
數字0到9,ASCII依次是48到57
大寫字母A到Z,ASCII依次是65到90
小寫字母a到z,ASCII依次是97到122
大小規則總結:
1)數字0~9比字母要小。如"7"<"F";
2)數字0比數字9要小,並按0到9順序遞增。如"3"<"8"
3)字母A比字母Z要小,並按A到Z順序遞增。如"A"<"Z"
4)同個字母的大寫字母比小寫字母要小。如"A"<"a"。
2. iso8859-1碼
iso8859-1通常叫做Latin-1,它和ascii編碼相似,都屬於單字節編碼,不同於ASCII的是,每個字節中的最高位也參與了編碼(如果最高位為0,它的意義同ASCII)。正因為如此,iso8859-1最多能表示的字符範圍是0-255,應用於英文係列。很明顯,iso8859-1編碼表示的字符範圍很窄,無法編碼中文字符。盡管如此,我們可以先把中文字符按照其它的編碼方式編碼成二進製數據,然後將編碼後的結果再逐字節逐字節的用iso8859-1解碼。也就是說,中文字符,它沒有iso8859-1編碼,但可以在用其它編碼方式編碼後的基礎上再用iso8859-1編碼來表示。舉個栗子,雖然“中文”的“中”這個字不存在iso8859-1編碼,可以先把它按gb2312編碼方式編碼為"d6d0"這個二字節的編碼(16進製),然後將它拆開為兩個字節("d6" 與 "d0"),每個字節都可以看作是一個iso8859-1碼。
iso8859-1編碼在網絡傳輸中的利用:
iso8859-1由於是單字節編碼,和計算機最基礎的表示單位一致,因此在很多網絡傳輸協議上,默認使用iso8859-1編碼。網絡上傳輸的數據都是二進製的,服務器從網絡io流中收到這些數據後,默認把每個字節的數據按iso8859-1編碼來處理。
實事上,通過網絡流傳輸中文時,客戶端可以先把中文字符按照其它的編碼方式(比如GBK或UTF-8)轉換成字節數據發送到服務器,服務器收到後在不指定編碼方式的情況下默認會逐個逐個字節的按照iso8859-1編碼方式來解碼。
寫點題外話,對於java web程序員來說,有時候可以在servlet代碼中看到類似於String str = new String(restr.getBytes("iso8859-1"),"utf-8");的轉換代碼,它的意思就是先把字符串restr通過restr.getBytes("iso8859-1")編碼為字節數組(restr是請求參數被按照iso8859-1方式解碼後的結果。如果請求參數為中文,因為iso8859-1編碼無法直接解碼中文,會導致解碼後的restr為亂碼),然後再按照utf-8的編碼方式重新轉換為一個新的字符串。
當然,在java web中也可以用request.setCharacterEncoding("utf-8");方法,直接告訴服務器按照指定的utf-8方式編碼。但值得一提的是在執行setCharacterEncoding()之前,不能執行任何getParameter(),而且,該指定隻對POST方法有效,對GET方法無效。原因是在執行第一個getParameter()的時候,java將會按照編碼分析所有的提交內容,而後續的getParameter()不再進行分析,所以setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析所有的提交內容,setCharacterEncoding()自然就無效。多說一句,為了避免總是要寫setCharacterEncoding("utf-8"),通常會在web.xml配置文件中配置一個最上層的字符編碼過濾器。
3. GB2312碼
無論是ascii碼還是iso8859-1碼,都無法直接編碼中文,於是有了GB2312碼。GB2312 是對 ASCII 的中文擴展,考慮到每個ASCII碼隻用了一個字節的底7位(高位為0),所以每個的ASCII碼都小於或等於127(01111111)。於是規定:一個小於127的字符的意義與原來相同(為了兼容ASCII碼),但兩個大於127的字符連在一起時,就表示一個漢字,而且這兩個字節中,前麵的一個字節(他稱之為高字節)從0xA1用到0xF7,後麵一個字節(低字節)從0xA1到0xFE,這樣我們可以組合出大約7000多個簡體漢字,這就是GB2312編碼。
這樣,計算機在解碼時,可以逐字節逐字節的判斷它的是否小於127,如果小於或等於127,就按ASCII直接解碼,如果大於127,就再往後多讀取一個字節,如果後麵那個字節也大於127,就把這兩個字節連起來再通過查找GB2312編碼碼表來解碼成一個中文字符。由此可見,GB2312碼是一種變長的編碼方式,英文占一個字節(而且小於127),中文占兩個字節(都是大於127的字節),而且兼容ASCII碼。
4. GBK碼
GB2312碼中用兩個連續的大於127字節的數據來表示一個中文,它能表示的數量剛好也就滿足簡體中文編碼的需要。後來發現,其實表示一個中文的兩個字符中,可以不要求兩個字節都大於127,隻要第一個字符大於127,就可以作為解碼中文的開始字符,第二個字符是否大於127都不會對計算機解碼造成二義性錯誤(在逐字節解碼的過程中,隻要讀到一個節字大於127,就直接往後再讀一個字節,不判斷第二個字節是否大於127就直接將這兩個字節連到一起然後再通過編碼碼表來解碼)。這樣,在GB2312碼的基礎上,通過不限定第二個字節是否大於127的方式擴展出了GBK碼。GBK包括了GB2312的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。
5. GB18030碼
在GBK碼的基礎上,再進一步擴展,增加了一些連續四個字節的漢字,於是也就有了GB18030碼,GB18030碼完全兼容GBK碼,而且增加了少數民族文字。
綜上所述,以上能表示中文的字符編碼中,可編碼的範圍從小到大依次是:ASCII < GB2312 < GBK < GB18030,而且它們後者兼容前者,其中GB2312和GBK用兩個字節表示中文,GB18030有些用兩個字節表示一個漢字,有些有兩個字節表示漢字。
6.UNICODE編碼
因為每個國家都搞出像天朝這樣一套自己的編碼標準,在跨國跨語言使用時存在儲多不便。為了統一,ISO(國際標誰化組織)重新搞了一套標準,也就是UNICODE編碼。
UNICODE這是最統一的定長編碼,有雙字節編碼(UCS-2)和四字節編碼(UCS-4,備用)兩種。其中UCS-2包括英文字母在內,隻能表示65535個字符,IOS預備的UCS-4方案,可以組合出21億個不同的字符出來(最高位有其他用途)。
其實,英文字母隻用一個字節表示就夠了,但是其他更大的符號可能需要3個字節或者4個字節,甚至更多。而Unicode統一規定,每個符號用兩個或四個字節表示,那麼每個英文字母前都必然有二到三個字節是0,這對於存儲來說其實是極大的浪費。
而且它不兼容iso8859-1編碼,也不兼容gb2312、gbk、gb18030等任何編碼。不過,相對於iso8859-1編碼來說,uniocode編碼隻是在前麵增加了一個0字節,比如字母a為"00 61"。
但是UNICODE這種定長編碼便於計算機處理(注意GB2312/GBK不是定長編碼),而unicode又可以用來表示所有字符,所以在很多軟件內部是使用unicode編碼來處理的,比如java。
需要注意的是,Unicode隻是一個符號集,它隻規定了符號的二進製代碼,卻沒有規定這個二進製代碼應該如何存儲。於是出現了多種存儲方式,也就是說有許多種不同的二進製格式,可以用來表示unicode。unicode在很長一段時間內無法推廣,直到互聯網的出現。
7.UTF
考慮到unicode編碼不兼容iso8859-1編碼,而且容易占用更多的空間:因為對於英文字母,unicode也需要兩個字節來表示。所以unicode不便於傳輸和存儲。因此而產生了utf編碼,utf編碼兼容iso8859-1編碼,同時也可以用來表示所有語言的字符,不過,utf編碼是不定長編碼,每一個字符的長度從1-6個字節不等。另外,utf編碼自帶簡單的校驗功能。
UTF-8是Unicode的實現方式之一,一般來講,對於UTF-8,英文字母都是用一個字節表示,而漢字使用三個字節。另外,還有UTF-16(字符用兩個字節或四個字節表示),UTF-32(字符用四個字節表示)。
顧名思義,UTF-8就是每次8個位傳輸數據,而UTF-16就是每次16個位。UTF-8就是在互聯網上使用最廣的一種unicode的實現方式,這是為傳輸而設計的編碼,並使編碼無國界,這樣就可以顯示全世界上所有文化的字符了。
UTF-8的編碼規則很簡單,隻有二條:
(1)對於單字節的符號,字節的第一位設為0,後麵7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
(2)對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,後麵字節的前兩位一律設為10。剩下的沒有提及的二進製位,全部為這個符號的unicode碼。
綜上所述,UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。而且UTF-8編碼的文件比GB2312更占空間大。
以上就是本人以常見字符編碼的匯總,正文中本文中紅色字體或加粗字體是需要重點理解或者記憶的。想了解更多信息,請關注本人公眾號
最後更新:2017-08-13 22:51:05