這篇文章主要介紹了下面三個問題:
1、什么是字符前痘、字符集凛捏、字符編碼,他們的區(qū)別區(qū)別是什么芹缔?
2坯癣、什么是UTF-8、UTF-16最欠、UTF-32示罗,他們的區(qū)別是什么?
3芝硬、什么是GB2312蚜点、GBK、GB18030拌阴,他們的區(qū)別是什么绍绘?
?編碼基本概念
1. 字符
字符(Character):在計算機和電信技術中,一個字符是一個單位的字形、類字形單位或符號的基本信息陪拘。說的簡單點字符是各種文字和符號的總稱厂镇。一個字符可以是一個中文漢字、一個英文字母左刽、一個阿拉伯數(shù)字捺信、一個標點符號、一個圖形符號或者控制符號等悠反。
2. 字符集
字符集(Character Set):是指多個字符的集合残黑。不同的字符集包含的字符個數(shù)不一樣、包含的字符不一樣斋否、對字符的編碼方式也不一樣梨水。例如GB2312是中國國家標準的簡體中文字符集,GB2312收錄簡化漢字(6763個)及一般符號茵臭、序號疫诽、數(shù)字、拉丁字母旦委、日文假名奇徒、希臘字母、俄文字母缨硝、漢語拼音符號摩钙、漢語注音字母,共 7445 個圖形字符查辩。而ASCII字符集只包含了128字符胖笛,這個字符集收錄的主要字符是英文字母、阿拉伯字母和一些簡單的控制字符宜岛。
另外长踊,還有其他常用的字符集有 GBK字符集、GB18030字符集萍倡、Big5字符集身弊、Unicode字符集等。
3. 字符編碼
字符編碼(Character Encoding):字符編碼是指一種映射規(guī)則列敲,根據(jù)這個映射規(guī)則可以將某個字符映射成其他形式的數(shù)據(jù)以便在計算機中存儲和傳輸阱佛。例如ASCII字符編碼規(guī)定使用單字節(jié)中低位的7個比特去編碼所有的字符,在這個編碼規(guī)則下字母A的編號是65(ASCII碼)戴而,用單字節(jié)表示就是0x41瘫絮,因此寫入存儲設備的時候就是二進制的 01000001。每種字符集都有自己的字符編碼規(guī)則填硕,常用的字符集編碼規(guī)則還有 UTF-8編碼麦萤、GBK編碼鹿鳖、Big5編碼等。
4. 碼點
碼點(Code Point):有些地方翻譯為碼值或內碼壮莹。是指在某個字符集中翅帜,根據(jù)某種編碼規(guī)則將字符編碼后得到的值。比如在ASCII字符集中命满,字母A經(jīng)過ASCII編碼得到的值是65涝滴,那么65就是字符A在ASCII字符集中的碼點。
總結:通俗解釋字符集就是把字符放到一起的一個集合胶台。而這個集合的每一個字符都對應一個數(shù)字歼疮,叫做碼點。那么诈唬,這樣就建立起來數(shù)字和字符之間的索引關系韩脏。那么,某個字符在計算機中怎么表示铸磅,具體占用幾個字節(jié)等等赡矢,這些就需要編碼規(guī)則來解決了。這個就是字符編碼阅仔,他來解決根據(jù)某個規(guī)則來將字符映射到相應的碼點上面吹散。
ASCII字符集
上個世紀60年代,美國制定了一套字符編碼規(guī)則八酒,對英語字符與二進制位之間的關系做了統(tǒng)一規(guī)定空民,這編碼規(guī)則被稱為ASCII編碼,一直沿用至今羞迷。
ASCII編碼一共規(guī)定了128個字符的編碼規(guī)則界轩,這128個字符形成的集合就叫做ASCII字符集。在ASCII編碼中闭树,每個字符占用一個字節(jié)的后面7位耸棒,最前面的1位統(tǒng)一規(guī)定為0荒澡。在ASCII編碼中报辱,0~31 是控制字符如換行回車刪除等,32~126 是可打印字符单山,可以通過鍵盤輸入并且能夠顯示出來碍现。(下圖是ASCII字符集中字符和碼值的對應關系)
英語用128個符號編碼就夠了,但是用來表示其他語言米奸,128個符號是不夠的昼接。所以當ASCII碼到歐洲的時候,一些歐洲國家就決定對ASCII編碼進行適當?shù)摹案脑臁保豪米止?jié)中閑置的最高位編入新的符號悴晰。比如慢睡,法語中的é的編碼為130(二進制10000010)逐工。這樣一來,這些歐洲國家使用的編碼體系漂辐,可以表示最多256個符號泪喊。這個編碼統(tǒng)稱為EASCII(Extended ASCII)。
但是歐洲的語言體系有個特點:小國家特別多髓涯,每個國家可能都有自己的語言體系袒啼,語言環(huán)境十分復雜。因此即使EASCII可以表示256個字符纬纪,也不能統(tǒng)一歐洲的語言環(huán)境蚓再。
為了解決上面這個問題,人們想出了一個折中的方案:在EASCII中表示的256個字符中包各,前128字符和ASCII編碼表示的字符完全一樣摘仅,后128個字符每個國家或地區(qū)都有自己的編碼標準。比如髓棋,130在法語編碼中代表了é实檀,在希伯來語編碼中卻代表了字母Gimel (?),在俄語編碼中又會代表另一個符號按声。但是不管怎樣膳犹,所有這些編碼方式中,0—127表示的符號是一樣的签则,不一樣的只是128—255的這一段须床。
根據(jù)這個規(guī)則,就形成了很多子標準:ISO-8859-1渐裂、ISO-8859-2豺旬、ISO-8859-3、……柒凉、ISO-8859-16族阅。這些子標準適用于歐洲不同的國家地區(qū)。具體關于ISO-8859的標準請參考這個鏈接膝捞。這邊我摘錄了部分介紹坦刀。
ISO8859-1 字符集,也就是 Latin-1蔬咬,是西歐常用字符鲤遥,包括德法兩國的字母。
ISO8859-2 字符集林艘,也稱為 Latin-2盖奈,收集了東歐字符。
ISO8859-3 字符集狐援,也稱為 Latin-3钢坦,收集了南歐字符究孕。
至于亞洲國家的文字,使用的符號就更多了爹凹,漢字就多達10萬左右蚊俺。一個字節(jié)最多只能表示256種符號,肯定是不夠的逛万,必須使用多個字節(jié)表達一個符號,因此才出現(xiàn)了后面的Unicode字符集和GB2312等字符集泳猬。比如,簡體中文常見的編碼方式是GB2312宇植,使用兩個字節(jié)表示一個漢字得封,所以理論上最多可以表示65536個符號。
總結:ASCII碼是美國制定的一套字符集指郁,里面包含128個字符(2^7)所有只用了7位忙上,最后一位默認賦值0,但是在一些歐洲國家為了滿足特殊符號需求闲坎,就把最后一位也用上了就多出來了128個字符(2^8)疫粥。個人理解:ASCII碼應該只是字符集,而不是字符編碼腰懂,或者曾經(jīng)是字符編碼梗逮,現(xiàn)在大家都是廣義上面說ASCII編碼。
Unicode字符集
ASCII碼字符集绣溜,總共才能容納256個字符慷彤,對于全世界各國語言來說,很難全部包含在內怖喻,所有后來就出現(xiàn)了Unicode字符集底哗。
Unicode字符集是一個很大的字符集合,現(xiàn)在的規(guī)拿校可以容納100多萬個符號跋选。每個符號的編碼都不一樣,比如哗蜈,U+0639表示阿拉伯字母Ain前标,U+0041表示英語的大寫字母A,U+4E25表示漢字“嚴”恬叹。
需要注意的是候生,Unicode只是一個字符集同眯,它只規(guī)定了符號的二進制代碼绽昼,卻沒有規(guī)定這個二進制代碼應該如何編碼如何存儲。這就造成了兩個問題:
第一個問題是须蜗,如何才能區(qū)別Unicode和ASCII硅确?計算機怎么知道三個字節(jié)表示一個符號目溉,而不是分別表示三個符號呢?
第二個問題是菱农,我們已經(jīng)知道缭付,英文字母只用一個字節(jié)表示就夠了,如果unicode統(tǒng)一規(guī)定循未,每個符號用三個或四個字節(jié)表示陷猫,那么每個英文字母前都必然有二到三個字節(jié)是0,這對于存儲來說是極大的浪費的妖,文本文件的大小會因此大出二三倍绣檬,這是無法接受的。
為了解決Unicode字符集存在的問題嫂粟,就出現(xiàn)了UTF(Unicode Transformation Formats)系列的編碼規(guī)則娇未。UTF編碼規(guī)則具體規(guī)定了Unicode字符集中的字符是如何編碼的。
總結:Unicode是一個很大的字符集星虹,這個字符集只規(guī)定了這個字符集中每個字符對應的碼值是多少零抬,但是這個字符集并沒有規(guī)定具體的編碼規(guī)則,具體的編碼規(guī)則有UTF系列的編碼規(guī)則實現(xiàn)宽涌。
下面我們就來看看UTF系列編碼的具體實現(xiàn)平夜。
UTF-8編碼
互聯(lián)網(wǎng)的普及,強烈要求出現(xiàn)一種統(tǒng)一的編碼方式卸亮。UTF-8就是在互聯(lián)網(wǎng)上使用最廣的一種Unicode的實現(xiàn)方式褥芒。其他實現(xiàn)方式還包括UTF-16和UTF-32,不過在互聯(lián)網(wǎng)上基本不用嫡良。重復一遍锰扶,這里的關系是:UTF-8編碼是Unicode的實現(xiàn)方式之一。
UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼規(guī)則寝受,又稱萬國碼坷牛。由Ken Thompson于1992年創(chuàng)建。現(xiàn)在已經(jīng)標準化為RFC 3629很澄。UTF-8用1到4個字節(jié)編碼Unicode字符京闰。用在網(wǎng)頁上可以統(tǒng)一頁面顯示中文簡體繁體及其它語言(如英文,日文甩苛,韓文)蹂楣。
UTF-8最大的一個特點,就是它是一種變長的編碼方式讯蒲。它可以使用1~4個字節(jié)表示一個符號痊土,根據(jù)不同的符號而變化字節(jié)長度(UTF-8編碼可以容納2^21個字符,總共200多萬個字符)墨林。
UTF-8的編碼規(guī)則很簡單赁酝,只有二條:
對于單字節(jié)的符號犯祠,字節(jié)的第一位設為0,后面7位為這個符號的unicode碼酌呆。因此對于英語字母衡载,UTF-8編碼和ASCII碼是相同的。
對于n字節(jié)的符號(n>1)隙袁,第一個字節(jié)的前n位都設為1痰娱,第n+1位設為0,后面字節(jié)的前兩位一律設為10菩收。剩下的沒有提及的二進制位猜揪,全部為這個符號的unicode碼。
下表總結了編碼規(guī)則坛梁,字母x表示可用編碼的位而姐。
Unicode符號范圍 | UTF-8編碼方式
UTF字節(jié)數(shù)???(十六進制) | (二進制)
一個字節(jié) 0000 0000-0000 007F | 0xxxxxxx
兩個字節(jié) 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
三個字節(jié) 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
四個字節(jié) 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
下面, 還是以漢字“嚴”為例划咐,演示如何實現(xiàn)UTF-8編碼拴念。
已知“嚴”的unicode是\u4E25(100111000100101),根據(jù)上表褐缠,可以發(fā)現(xiàn)4E25處在第三行的范圍內(0000 0800-0000 FFFF)政鼠,因此“嚴”的UTF-8編碼需要三個字節(jié),即格式是“1110xxxx 10xxxxxx 10xxxxxx”队魏。然后公般,從“嚴”的最后一個二進制位開始,依次從后向前填入格式中的x胡桨,多出的位補0官帘。這樣就得到了,“嚴”的UTF-8編碼是“11100100 10111000 10100101”昧谊,轉換成十六進制就是E4B8A5刽虹。
UTF8、UTF16和UTF32之間的區(qū)別
再次強調一個概念:就是Unicode是一個字符集呢诬,這個字符集世界上所有的字符定義了一個唯一編碼涌哲。其僅僅規(guī)定了每個符號的二進制代碼,沒有制定細化的存儲規(guī)則尚镰。UTF-8阀圾、UTF-16、UTF-32才是Unicode的存儲格式定義狗唉。上面已經(jīng)簡單介紹了UTF8編碼規(guī)則初烘,那么這個規(guī)則和UTF16、UTF32等規(guī)則有什么區(qū)別呢?
UCS-2和UCS-4
在將UTF8和UTF16账月、UTF32的區(qū)別之前,再先科普兩個名詞:UCS-2和UCS-4澳迫。
Unicode是為整合全世界的所有語言文字而誕生的局齿。任何文字在Unicode中都對應一個值,?這個值稱為代碼點(code point橄登,也稱碼值)抓歼。代碼點的值通常寫成 U+ABCD 的格式。而文字和代碼點之間的對應關系就是UCS-2(Universal Character Set coded in 2 octets)拢锹。顧名思義谣妻,UCS-2是用兩個字節(jié)來表示代碼點,其取值范圍為 U+0000~U+FFFF卒稳。
為了能表示更多的文字蹋半,人們又提出了UCS-4,即用四個字節(jié)表示代碼點充坑。它的范圍為 U+00000000~U+7FFFFFFF减江,其中 U+00000000~U+0000FFFF和UCS-2是一樣的。
要注意捻爷,UCS-2和UCS-4只規(guī)定了代碼點和文字之間的對應關系辈灼,并沒有規(guī)定代碼點在計算機中如何存儲。規(guī)定存儲方式的稱為UTF(Unicode Transformation Format)也榄,也就是我們上面提到的UTF8格式和下面將要提到的UTF16巡莹、UTF32格式。
UTF-16編碼格式
UTF-16由RFC2781規(guī)定甜紫,它使用兩個字節(jié)來表示一個代碼點降宅。不難猜到,UTF-16是完全對應于UCS-2的囚霸,即把UCS-2規(guī)定的代碼點通過Big Endian或Little Endian方式直接保存下來钉鸯。UTF-16包括三種:UTF-16,UTF-16BE(Big Endian)和UTF-16LE(Little Endian)邮辽。UTF-16BE和UTF-16LE不難理解岩睁,而UTF-16就需要通過在文件開頭以名為BOM(Byte Order Mark)的字符來表明文件是Big Endian還是Little Endian揣云。BOM為U+FEFF這個字符。其實BOM是個小聰明的想法。由于UCS-2沒有定義U+FEFF扇调,因此只要出現(xiàn) FF FE 或者 FE FF 這樣的字節(jié)序列,就可以認為它是U+FEFF,并且可以判斷出是Big Endian還是Little Endian涎拉。
BOM(Byte Order Mark)用來放在文檔的開頭告訴閱讀器該文檔的字節(jié)序略板。UTF-8不需要BOM來表明字節(jié)順序种玛,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節(jié)流质涛,就知道這是UTF-8編碼了带饱。UTF-16才需要加BOM捏鱼。因為它是按Unicode 順序編碼,在BMP范圍內是二字節(jié)猿诸,需要識別是大或小字節(jié)序址芯。
這邊順便科普下大小端的概念旬陡。
低字節(jié)序(Little Endian)和高字節(jié)序(Big Endian)
低字節(jié)序和高字節(jié)序只是一個關于在內存中存儲和讀取一段字節(jié)(被稱作words)的約定砰左。這意味著當你讓計算機用UTF-16把字母A(占兩個字節(jié))存在內存中時,使用哪種字節(jié)序方案決定了你把第一個字節(jié)放在第二個字節(jié)的前面還是后面。這么說有點不太容易懂,讓我們來看一個例子:當你使用UTF-16存下某段內容時,在不同的系統(tǒng)中它的后半部分可能是這樣的:
00 68?00 65?00 6C?00 6C?00 6F(高字節(jié)序忍些,高位字節(jié)被存在前面)
68 00?65 00?6C 00?6C 00?6F 00(低字節(jié)序,低位字節(jié)被存在前面)
字節(jié)序方案只是一個微處理器架構設計者的偏好問題坎怪,例如罢坝,Intel使用低字節(jié)序嘁酿,Motorola使用高字節(jié)序沐飘。
舉個例子铐刘「┘瑁“ABC”這三個字符用各種方式編碼后的結果如下:
編碼類型碼值
UTF-32
UTF-32用四個字節(jié)表示代碼點捡遍,這樣就可以完全表示UCS-4的所有代碼點画株,而無需像UTF-8那樣使用復雜的算法啦辐。?與UTF-16類似谓传,UTF-32也包括UTF-32、UTF-32BE芹关、UTF-32LE三種編碼续挟,UTF-32也同樣需要BOM字符。
文本編輯器怎么知道文本的編碼
當一個軟件打開一個文本時侥衬,它要做的第一件事是決定這個文本究竟是使用哪種字符集的哪種編碼保存的诗祸。軟件一般采用三種方式來決定文本的字符集和編碼:
檢測文件頭標識(BOM)
EF ? BB ? BF ? UTF-8 ? ???
FE ? FF ? UTF-16/UCS-2, ? big ? endian ? ???
FF ? FE ? UTF-16/UCS-2, ? little ? endian ? ???
FF ? FE ? 00 ? 00 ? UTF-32/UCS-4, ? little ? endian. ? ???
00 ? 00 ? FE ? FF ? UTF-32/UCS-4, ? big-endian.
軟件自己根據(jù)編碼規(guī)則猜測當前文件的編碼
提示用戶自己輸入當前文件的編碼
總結:UTF-8跑芳、UTF-16、UTF-32只是一種編碼格式直颅,不是字符集博个,是用來規(guī)范字符集存儲用的。其中UTF-8是變成的編碼規(guī)范功偿,而UTF-16是固定用兩個字節(jié)表示一個碼值盆佣,UTF-32是固定使用四個字節(jié)表示一個碼值。
GB2312械荷、GBK共耍、GB18030之間的區(qū)別
GB2312編碼是第一個漢字編碼國家標準,是由中國國家標準總局1980年發(fā)布吨瞎,1981年5月1日開始實施的一套國家標準痹兜,標準號是GB2312—1980。GB2312編碼適用于漢字處理关拒、漢字通信等系統(tǒng)之間的信息交換佃蚜,通行于中國大陸庸娱;新加坡等地也采用此編碼着绊。中國大陸幾乎所有的中文系統(tǒng)和國際化的軟件都支持GB2312。GB2312編碼共收錄漢字6763個熟尉,其中一級漢字3755個归露,二級漢字3008個。同時斤儿,GB2312編碼收錄了包括拉丁字母剧包、希臘字母、日文平假名及片假名字母往果、俄語西里爾字母在內的682個全角字符疆液。
GB2312是對ASCll碼的擴展,占用兩個字節(jié)陕贮。具體的編碼規(guī)則這邊就不介紹了堕油,感興趣的讀者可以參考這篇博客。
GB2312能表示的漢字只有6000多個肮之,但是中國的漢字有10萬之多掉缺,所以GB2312字符集還是不夠用,于是GBK出現(xiàn)了戈擒。GBK是對GB1212的擴展眶明,也是占用2個字節(jié),GBK不再要求低字節(jié)一定是127號之后的內碼筐高,只要第一個字節(jié)是大于127就固定表示這是一個漢字的開始搜囱,不管后面跟的是不是擴展字符集里的內容丑瞧。GBK 包括了 GB2312 的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號蜀肘。
GB18030采用變長編碼嗦篱,可以是1個字節(jié)、2個字節(jié)和4個字節(jié)幌缝。是對GB2312和GBK的擴展灸促,完全兼容兩者。
通過上面介紹涵卵,可以發(fā)現(xiàn)GBK浴栽、GB2312和GB18030字符集主要是對中文漢字的編碼,同時兼顧了一些其他常用符號的編碼轿偎。其中:
GB2312編碼方案出現(xiàn)最早典鸡,占用2個字節(jié),但是能表示的字符較少坏晦;
GBK也占用2個字節(jié)萝玷,采用了不同的編碼方式,對GB2312進行了擴展昆婿,增加了近20000個新的漢字(包括繁體字)和符號球碉;
GB18030采用變長編碼,可以是1個字節(jié)仓蛆、2個字節(jié)和4個字節(jié)睁冬。是對GB2312和GBK的擴展,完全兼容兩者看疙。
總結:GB2312是我們中文自己的字符集豆拨,是國家標準。由于不能包含全部漢字能庆,后面有擴展出現(xiàn)了GBK施禾,GBK是固定長度編碼的字符集,后面又出現(xiàn)了變長編碼的GB18030字符集搁胆。