由于“字符編碼”這個話題牽涉到的歷史久遠(yuǎn)、機(jī)構(gòu)眾多、專業(yè)術(shù)語較多,所以本篇文章可能會略長,為了避免內(nèi)容過于枯燥,盡量用一種通俗易懂的語言來寫這篇文章。
完成本篇文章的過程中參考和閱讀了大量的文章和文獻(xiàn),寫本篇文章的目的一是讓大家對“字符編碼”能夠做一個較深的理解,二是希望給曾經(jīng)徘徊或正在徘徊在編碼困惑中的前端們一個很好的參考,搞清楚字符編碼問題是前端萬事之基石。
跟隨歷史的足跡看字符編碼
古代的通信方式
很久很久以前,人們之間的長途通訊主要是用信鴿、騎馬送報、烽煙等方式進(jìn)行:
不過這些方式無不例外都是出奇的慢,同時也受天氣、地理等因素的影響。
世界第一條電報
直到1837年,世界第一條電報誕生,當(dāng)時美國科學(xué)家莫爾斯嘗試用一些“點”和“劃”來表示不同的字母、數(shù)字和標(biāo)點符號,這套表示字符的方式也被稱為“摩爾斯電碼”:
世界第一臺計算機(jī)
再后來到了1946年,世界第一臺計算機(jī)誕生。發(fā)明計算機(jī)的同學(xué)們用8個晶體管的“通”或“斷”組合出一些狀態(tài)來表示世間萬物,不過當(dāng)時的計算機(jī)有一間半教室那么大,六頭大象重,從現(xiàn)在看來這簡直就是個怪物,但在當(dāng)時卻是震驚世界與改變世界的一項重要發(fā)明:
ASCII
8個晶體管的“通”或“斷”即可以代表一個字節(jié),剛開始,計算機(jī)只在美國使用,所有的信息在計算機(jī)最底層都是以二進(jìn)制(“0”或“1”兩種不同的狀態(tài))的方式存儲,而8位的字節(jié)一共可以組合出256(2的8次方)種狀態(tài),即256個字符,這對于當(dāng)時的美國已經(jīng)是足夠的了,他們嘗試把一些終端的動作、字母、數(shù)字和符號用8位(bit)來組合:
0000 0000 ~ 0001 1111 共 33 種狀態(tài)用來表示終端的特殊動作,如打印機(jī)中的響鈴為 0000 0111 ,當(dāng)打印機(jī)遇到 0000 0111 這樣的字節(jié)傳過來時,打印機(jī)就開始響鈴;
0010 0000 ~ 0010 1111 、 0011 1010~0110 0000 和 0111 1101 ~ 0111 1110 共 33 種狀態(tài)來表示英式標(biāo)點符號,如 0011 1111 既代表英式問號“?”;
0011 0000 ~ 0011 1001 共 10 種狀態(tài)來表示“0~9”10個阿拉伯?dāng)?shù)字;
0100 0001 ~ 0101 1010 和 0110 0001 ~ 0111 1010共 52種狀態(tài)來表示大小寫英文字母;
自此,一共只用到了128種狀態(tài),即128個字符,剛好占用了一個字節(jié)中的后7位,共包括33個控制字符和95個可顯示字符,這一字符集被稱為ASCII(American Standard Code for Information Interchange,美國信息交換標(biāo)準(zhǔn)代碼),這一套字符集在1967年被正式公布。
講到這里,引出幾個基礎(chǔ)概念:
比特(bit):也可稱為“位”,是計算機(jī)信息中的最小單位,是 binary digit(二進(jìn)制數(shù)位) 的 縮寫,指二進(jìn)制中的一位
字節(jié)(Byte):計算機(jī)中信息計量的一種單位,一個位就代表“0”或“1”,每8個位(bit)組成一個字節(jié)(Byte)
字符(Character):文字與符號的總稱,可以是各個國家的文字、標(biāo)點符號、圖形符號、數(shù)字等
字符集(Character Set):是多個字符的集合
編碼(Encoding): 信息從一種形式或格式轉(zhuǎn)換為另一種形式的過程
解碼(decoding): 編碼的逆過程
字符編碼(Character Encoding): 按照何種規(guī)則存儲字符
現(xiàn)在我們來看我們文章開頭提到的第一條電報的誕生,莫爾斯編碼中包含了大小寫英文字母和數(shù)字等符號。
這里的每一個符號其實就是?字符?,
而這所有的字符的集合就叫做?字符集?,
“點”或“劃”與字符之間的對應(yīng)關(guān)系即可以稱為?字符編碼?。
電報的原理:
“點”對應(yīng)于短的電脈沖信號,“劃”對應(yīng)于長的電脈沖信號,這些信號傳到對方,接收機(jī)把短的電脈沖信號翻譯成“點”,把長的電脈沖信號轉(zhuǎn)換成“劃”,譯碼員根據(jù)這些點劃組合就可以譯成英文字母,從而完成了通信任務(wù)。
這里把字符表示為“點”或“劃”并對應(yīng)為電脈沖信號的過程既是?編碼?,
而譯碼員把接收機(jī)接收到的脈沖信號轉(zhuǎn)化成點劃后譯成字符的過程即為?解碼?。
而對于計算機(jī)誕生之后,只不過是將摩斯電碼中的“點”和“劃”換成了以8位字節(jié)二進(jìn)制流的方式表示,如數(shù)字1的二進(jìn)制流是0011 0001,對應(yīng)的十進(jìn)制流是49,十六進(jìn)制流是31。
EASCII
雖然剛開始計算機(jī)只在美國使用,128個字符的確是足夠了,但隨著科技驚人的發(fā)展,歐洲國家也開始使用上計算機(jī)了。不過128個字符明顯不夠呀,比如法語中,字母上方有注音符號,于是,一些歐洲國家就決定,利用字節(jié)中閑置的最高位編入新的符號。比如,法語的é的二進(jìn)制流為1000 0010,這樣一來,這些歐洲國家的編碼體系,可以表示最多256個字符了。
但是,這里又出現(xiàn)了新的問題。不同的國家有不同的字母,因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。比如,1000 0010在法語編碼中代表了é,在希伯來語編碼中卻代表了字母Gimel (?),在俄語編碼中又會代表另一個符號。但是不管怎樣,所有這些編碼方式中,0–127表示的符號是一樣的,不一樣的只是128–255的這一段。
EASCII(Extended ASCII,延伸美國標(biāo)準(zhǔn)信息交換碼)由此應(yīng)運(yùn)而生,EASCII碼比ASCII碼擴(kuò)充出來的符號包括表格符號、計算符號、希臘字母和特殊的拉丁符號:
GB2312
EASCII碼對于部分歐洲國家基本夠用了,但過后的不久,計算機(jī)便來到了中國,要知道漢字是世界上包含符號最多并且也是最難學(xué)的文字。
據(jù)不完全統(tǒng)計,漢字共包含了古文、現(xiàn)代文字等近10萬個文字,就是我們現(xiàn)在日常用的漢字也有幾千個,那么對于只包含256個字符的EASCII碼也難以滿足天朝的需求了。
于是?中國國家標(biāo)準(zhǔn)總局?(現(xiàn)已更名為?國家標(biāo)準(zhǔn)化管理委員會?)在1981年,正式制訂了中華人民共和國國家標(biāo)準(zhǔn)簡體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,項目代號為GB 2312 或 GB 2312-80(GB為國標(biāo)漢語拼音的首字母),此套字符集于當(dāng)年的5月1日起正式實施。
包含字符:
共包含7445個字符,6763個漢字和682個其他字符(拉丁字母、希臘字母、日文平假名及片假名字母、俄語西里爾字母)
存儲方式:
基于EUC存儲方式,每個漢字及符號以兩個字節(jié)來表示,第一個字節(jié)為“高位字節(jié)”,第二個字節(jié)為“低位字節(jié)”
BIG5
要知道港澳臺同胞使用的是繁體字,而中國大陸制定的GB2312編碼并不包含繁體字,于是信息工業(yè)策進(jìn)會在1984年與臺灣13家廠商簽定“16位個人電腦套裝軟件合作開發(fā)(BIG-5)計劃”,并開始編寫并推出BIG5標(biāo)準(zhǔn)。
之后推出的倚天中文系統(tǒng)則基于BIG5碼,并在臺灣地區(qū)取得了巨大的成功。在BIG5誕生后,大部分的電腦軟件都使用了Big5碼,BIG5對于以臺灣為核心的亞洲繁體漢字圈產(chǎn)生了久遠(yuǎn)的影響,以至于后來的window 繁體中文版系統(tǒng)在臺灣地區(qū)也基于BIG5碼進(jìn)行開發(fā)。
包含字符:
共收錄13,060個漢字及441個符號
編碼方式:
用兩個字節(jié)來為每個字符編碼,第一個字節(jié)稱為“高位字節(jié)”,第二個字節(jié)稱為“低位字節(jié)”
Unicode
由來:
在計算機(jī)進(jìn)入中國大陸的相同時期,計算機(jī)也迅速發(fā)展進(jìn)入了世界各個國家。
特別是對于亞洲國家而言,每個國家都有自己的文字,于是每個國家或地區(qū)都像中國大陸這樣去制定了自己的編碼標(biāo)準(zhǔn),以便能在計算機(jī)上正確顯示自己國家的符號。
但帶來的結(jié)果就是國家之間誰也不懂別人的編碼,誰也不支持別人的編碼,連大陸和臺灣這樣只相隔了150海里,都使用了不同的編碼體系。
于是,世界相關(guān)組織意識到了這個問題,并開始嘗試制定統(tǒng)一的編碼標(biāo)準(zhǔn),以便能夠收納世界所有國家的文字符號。
在前期有兩個嘗試這一工作的組織:
國際標(biāo)準(zhǔn)化組織(ISO)
統(tǒng)一碼聯(lián)盟
國際標(biāo)準(zhǔn)化組織(ISO)及國際電工委員會(IEC)于1984年聯(lián)合成立了ISO/IEC小組,主要用于開發(fā)統(tǒng)一編碼項目;
而Xerox、Apple等軟件制造商則于1988年組成了統(tǒng)一碼聯(lián)盟,用于開發(fā)統(tǒng)一碼項目。
兩個組織都在編寫統(tǒng)一字符集,但后來他們發(fā)現(xiàn)各自在做相同的工作,同時世界上也不需要兩個不兼容的字符集,于是兩個組織就此合并了雙方的工作成果,并為創(chuàng)立一個單一編碼表而協(xié)同工作。
1991年,兩個組織共同的工作成果Unicode 1.0正式發(fā)布,不過Unicode 1.0并不包含CJK字符(即中日韓)。
版本歷史:
Unicode 1.0:1991年10月
Unicode 1.0.1:1992年6月
Unicode 1.1:1993年6月
Unicode 2.0:1997年7月
Unicode 2.1:1998年5月
Unicode 2.1.2:1998年5月
Unicode 3.0:1999年9月
Unicode 3.1:2001年3月
Unicode 3.2:2002年3月
Unicode 4.0:2003年4月
Unicode 4.0.1:2004年3月
Unicode 4.1:2005年3月
Unicode 5.0:2006年7月
Unicode 5.1:2008年4月
Unicode 5.2:2009年10月
Unicode 6.0:2010年10月
Unicode 4.1:2005年3月
Unicode 6.1:2012年1月31日
Unicode 6.2:2012年9月
ISO/IEC 8859
ISO/IEC小組在1984年成立后的第三年(即1987年)開始啟動ISO 8859標(biāo)準(zhǔn)的編寫,ISO 8859是一系列8位字符集的標(biāo)準(zhǔn),主要為世界各地的不同語言(除CJK)而單獨(dú)編寫的字符集,一共定義了15個字符集:
ISO/IEC 8859-1:西歐語言
ISO/IEC 8859-2 :中歐語言
ISO/IEC 8859-3 :南歐語言
ISO/IEC 8859-4: 北歐語言
ISO/IEC 8859-5: 斯拉夫語
ISO/IEC 8859-6: 阿拉伯語
ISO/IEC 8859-7:希臘語
ISO/IEC 8859-8:希伯來語
ISO/IEC 8859-9:土耳其語
ISO/IEC 8859-10: 北日耳曼語
ISO/IEC 8859-11:泰語
ISO/IEC 8859-13: 波羅的語族
ISO/IEC 8859-14: 凱爾特語族
ISO/IEC 8859-15:西歐語言,收錄芬蘭語字母和大寫法語重音字母,以及歐元(€)符號
ISO/IEC 8859-16 :東南歐語言,主要供羅馬尼亞語使用,并加入歐元(€)符號
其中ISO/IEC 8859-1至ISO/IEC 8859-4四個項目早在1982年就已經(jīng)編寫出來,只不過是由ANSI與ECMA合作完成,并于1985年正式公布,ISO/IEC小組成立后,這一成果被其收錄,并改名為ISO/IEC 8859 前四個項目。
大家其實發(fā)現(xiàn)以上15個字符集中并沒有代號為“ISO/IEC 8859 -12”的字符集,據(jù)說-12號本來是預(yù)留給印度天城體梵文的,但后來卻擱置了(阿三有了自己的編碼-ISCII)。由于英語沒有任何重音字母,故可使用以上十五個字符集中的任何一個來表示。
ISO/IEC 10646 / UCS
1993年,ISO/IEC 10646標(biāo)準(zhǔn)第一次發(fā)表,ISO/IEC 10646是ISO 646的擴(kuò)展,定義了1個31位的字符集。ISO 10646標(biāo)準(zhǔn)中定義的字符集為UCS,UCS是Universal Character Set的縮寫,中文譯作通用字符集。
版本:
ISO/IEC 10646-1:第一次發(fā)表于1993年,現(xiàn)在的公開版本是2000年發(fā)表的ISO/IEC 10646-1:2000。
ISO/IEC 10646-2:在2001年發(fā)表。
包含字符:
最初的ISO 10646-1:1993的編碼標(biāo)準(zhǔn),即Unicode 1.1,收錄中國大陸、臺灣、日本及韓國通用字符集的漢字共計20,902個,當(dāng)然每個版本的Unicode標(biāo)準(zhǔn)的字符集所包含的字符數(shù)不盡相同,UCS 包含了已知語言的所有字符,除了拉丁語、希臘語、斯拉夫語、希伯來語、阿拉伯語、亞美尼亞語、格魯吉亞語,還包括中文、日文、韓文這樣的方塊文字,此外還包括了大量的圖形、印刷、數(shù)學(xué)、科學(xué)符號。
UCS給每個字符分配一個唯一的代碼,并且賦予了一個正式的名字,通常在表示一個Unicode值的十六進(jìn)制數(shù)的前面加上“U+”,例如“U+0041”代表字符“A”。
編碼方案:
UCS僅僅是一個超大的字符集,關(guān)于UCS制定的編碼方案有兩種:UCS-2和UCS-4,Unicode默認(rèn)以UCS-2編碼。
顧名思義,UCS-2就是用兩個字節(jié)編碼,UCS-4就是用4個字節(jié)(實際上只用了31位,最高位必須為0)編碼。那么UCS-2其實可以容納的字符數(shù)為65536(2的16次方),而UCS-4可以容納的字符數(shù)為2147483648(2的31次方)。其實對于UCS-2已經(jīng)是完全夠用了,基本可以包含世界所有國家的常用文字,如果需要考慮一些偏僻字,那么UCS-4則絕對可以滿足了,21億個字符哪怕是整個宇宙也夠用了吧!
UTF
Unicode 誕生,隨之而來的計算機(jī)網(wǎng)絡(luò)也發(fā)展了起來,Unicode 如何在網(wǎng)絡(luò)上傳輸也是一個必須考慮的問題,于是在1992年,面向網(wǎng)絡(luò)傳輸?shù)腢TF標(biāo)準(zhǔn)出現(xiàn)了。
UTF是Unicode Transformation Format的縮寫,中文譯作Unicode轉(zhuǎn)換格式。其實我們從現(xiàn)在可以把Unicode看作是一個標(biāo)準(zhǔn)或組織,而UCS就是一個字符集,那么UCS在網(wǎng)絡(luò)中的傳輸標(biāo)準(zhǔn)就是UTF了。
前面提到了UCS的編碼實現(xiàn)方式為UCS-2和UCS-4,即要么是每個字符為2個字節(jié),要么是4個字節(jié)。如果一個僅包含基本7位ASCII字符的 Unicode文件,每個字符都使用2字節(jié)的原Unicode編碼傳輸,其第一字節(jié)的8位始終為0,這就造成了比較大的浪費(fèi)。但是,聰明的人們發(fā)明了 UTF-8,UTF-8采用可變字節(jié)編碼,這樣可以大大節(jié)省帶寬,并增加網(wǎng)絡(luò)傳輸效率。
UTF-8
使用1~4個字節(jié)為每個UCS中的字符編碼:
128個ASCII字符只需一個字節(jié)編碼(Unicode范圍由U+0000至U+007F)
拉丁文、希臘文、西里爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及它拿字母需要二個字節(jié)編碼(Unicode范圍由U+0080至U+07FF)
大部分國家的常用字(包括中文)使用三個字節(jié)編碼
其他極少使用的生僻字符使用四字節(jié)編碼
UTF-16/UCS-2
UCS-2的父集,使用2個或4個字節(jié)來為每個UCS中的字符編碼:
128個ASCII字符需兩個字節(jié)編碼
其他字符使用四個字節(jié)編碼
UTF-32/UCS-4
等同于UCS-4,對于所有字符都使用四個字節(jié)來編碼
GB13000
前面提到了Unicode的迅速發(fā)展,至1993年時,包含CJK的Unicode 1.1已經(jīng)發(fā)布了,天朝的ZF也意識到了需要一個更大的字符集來走向世界,于是在同一年,中國大陸制定了幾乎等同于Unicode1.1的 GB13000.1-93國家編碼標(biāo)準(zhǔn)(簡稱GB13000)。是的,你沒聽錯,中華人民共和國信息產(chǎn)業(yè)部把Unicode里的所有東東拿過來,然后自己重新修訂發(fā)布了下,改為了國家標(biāo)準(zhǔn)GB13000。此標(biāo)準(zhǔn)等同于 ISO/IEC 10646.1:1993和Unicode 1.1。
GBK
1995年,在GB13000誕生后不久,中國教育科研網(wǎng)(NCFC)與美國NCFnet直接聯(lián)網(wǎng),這一天是中國被國際承認(rèn)為開始有網(wǎng)際網(wǎng)路的時間。此后網(wǎng)絡(luò)正式開始在中國大陸接通,個人計算機(jī)開始在中國流行,雖然當(dāng)時只是高富帥才消費(fèi)得起的產(chǎn)品。中國是一個十幾億人口的大國,微軟意識到了中國是一個巨大的市場,當(dāng)時的微軟也將自己的操作系統(tǒng)市場布局進(jìn)中國,進(jìn)入中國隨之而來要解決的就是系統(tǒng)的編碼兼容問題。
之前的國家編碼標(biāo)準(zhǔn)GB 2312,基本滿足了漢字的計算機(jī)處理需要,它所收錄的漢字已經(jīng)覆蓋中國大陸99.75%的使用頻率。但對于人名、古漢語等方面出現(xiàn)的罕用字和繁體字,GB 2312不能處理,因此微軟利用了GB2312中未使用的編碼空間,收錄了GB13000中的所有字符制定了漢字內(nèi)碼擴(kuò)展規(guī)范GBK(K為漢語拼音 Kuo Zhan中“擴(kuò)”字的首字母)。所以這一關(guān)系其實是大陸把Unicode1.1借鑒過來改名為了GB13000,而微軟則利用GB2312中未使用的編碼空間收錄GB13000制定了GBK。所以GBK是向下完全兼容GB2312的。
包含字符:
共收錄21886個字符, 其中漢字21003個, 字符883個
編碼方式:
GBK只不過是把GB2312中未使用的空間,編碼了其他字符,所以GBK同樣是用兩個字節(jié)為每個字符進(jìn)行編碼。
GB18030
微軟到了99年前后,說GBK已經(jīng)落伍了,現(xiàn)在流行UTF-8標(biāo)準(zhǔn),準(zhǔn)備全盤轉(zhuǎn)換成UTF-8,但中國ZF不是吃素的,編寫并強(qiáng)制推出了 GB18030標(biāo)準(zhǔn)。GB18030的誕生還有一個原因是GBK只包含了大部分的漢字和繁體字等,我們的少數(shù)民族兄弟根本木有考慮!中國有56個民族,其中有12個民族有自己的文字,那怎么辦呢?在2000年,電子工業(yè)標(biāo)準(zhǔn)化研究所起草了GB18030標(biāo)準(zhǔn),項目代號“GB 18030-2000”,全稱《信息技術(shù)-信息交換用漢字編碼字符集-基本集的擴(kuò)充》。此標(biāo)準(zhǔn)推出后,在中國大陸之后的所售產(chǎn)品必須強(qiáng)制支持GB18030標(biāo)準(zhǔn),不然不得賣!(這招挺狠的 – -#)
版本:
GB 18030-2000
GB 18030-2005
包含字符:
GB18030收錄了GBK中的所有字符,并將Unicode中其他中文字符(少數(shù)民族文字、偏僻字)也一并收錄進(jìn)來重新編碼。其中GB 18030-2000共收錄27533個漢字,而GB 18030-2005共包含70244個漢字。
編碼方式:
采用多字節(jié)編碼,每個字符由1或2或4個字節(jié)進(jìn)行編碼
前端眼中的字符編碼
前面我們穿越回過去對字符編碼做了下了解,那么這些字符編碼跟我們到底有啥關(guān)系?
基本原理:
當(dāng)我們打開編輯器coding時,按下ctrl+s的那一刻,其實等于是將自己的工作成果存儲進(jìn)了計算機(jī),而這里最關(guān)鍵的是我們以什么字符編碼來進(jìn)行存儲,我們以intellij編輯器為例:
我們在編寫此文檔時,是以UTF-8編碼方式進(jìn)行coding,當(dāng)我們按下ctrl+s時,則此文檔以utf-8編碼方式存儲進(jìn)了計算機(jī)(右下角的UTF-8),而head區(qū)域中的的作用則是告訴瀏覽器此文檔以utf-8編碼方式編碼。
我們此時用Hex編輯器打開這個文件,來看看他的二進(jìn)制流:
其中紅框標(biāo)注出的即為“小海”兩個中文字的二進(jìn)制流,第一個為”11100101 10110000 10001111″轉(zhuǎn)化為十六進(jìn)制則為“E5B08F”,第二個為“10110101 10110111 00001101”轉(zhuǎn)化為十六進(jìn)制為“E6B5B7”,而當(dāng)我們?nèi)ゲ樵僓TF-8的碼表時發(fā)現(xiàn)“E5B08F”對應(yīng)的字符為“小”,“E6B5B7”對應(yīng)的字符則為“?!保链水?dāng)我們用瀏覽器進(jìn)行預(yù)覽頁面時,由于瀏覽器同樣以UTF-8方式對此頁面進(jìn)行解碼,“小?!眱蓚€字則可以被正確的顯示出來。
亂碼是個XX
做過前端的基本都遇到過亂碼問題吧?好吧,下面就帶大家來揭開這一神秘的面紗。
我們用notepad打開上面的文件,并重新以GBK方式編碼,然后用intellij打開后:
亂了有木有!居然變成了“C??”,木有道理呀!我在用notepad編輯文件時采用的是gbk編碼,而頭部申明的也是gbk,本身notepad打開也是正常,但用intellij打開卻亂了!
罪魁禍?zhǔn)祝壕庉嬈髂J(rèn)編碼。每個編輯器都會有默認(rèn)編碼,如果沒有為一個項目單獨(dú)設(shè)置過默認(rèn)編碼,打開一個單獨(dú)的文件,編輯器往往以自己的默認(rèn)編碼去解碼這個文件,如上圖,我們的inellij編輯器的默認(rèn)是UTF-8解碼,而文件是GBK編碼方式,那么打開肯定就是亂的拉。
所以編輯器也是一個因素,DW則可以智能判斷文件的編碼方式,上述文件用DW打開并不會亂碼,而intellij可能對中文的支持并不是很好,所以還不能智能判斷中文編碼,默認(rèn)以UTF-8解碼(當(dāng)然默認(rèn)編碼自己是可以修改的)。
很多讀者可能還有一個疑問,為啥亂碼出來的是“C??”?
其實原理已在上面的基本原理中做過介紹,即編輯器ctrl+s存進(jìn)計算機(jī)時是GBK,但嘗試用utf-8來解析,對應(yīng)的utf-8中的碼表中卻找到了“C??”,感興趣的同學(xué)可以自己研究下。
我們現(xiàn)在將文件重新編輯,即編輯時采用GBK,但頭部申明為UTF-8:
然后用瀏覽器打開后,就是這樣了:
亂了有木有!這個其實和編輯器打開一個文件亂碼的原理是一致的:即編輯器編碼時所采用的字符編碼和解碼時所采用的字符編碼不一致。上述栗子,我們在coding時采用的是GBK編碼,但頭部卻告訴瀏覽器這個文檔是UTF-8編碼,那么瀏覽器在用UTF-8解碼時就會出現(xiàn)了亂碼。
申明編碼的方式
我們在coding時需要告訴瀏覽器自己的文件采用了什么字符編碼,下面列出一些常見的方法:
//html5
//html4 xhtml
我們可以在head區(qū)域的meta元素中為整個頁面申明編碼方式
,也可以為單獨(dú)的外鏈文件申明編碼方式(link/script等元素)。問題是如果頁面頭部和外鏈文件中只有部分申明或者全部申明,那么對應(yīng)的到底是以什么方式解碼呢?這里就有一個優(yōu)先級的問題,具體的判定關(guān)系如下:
通過上述判定,我們其實可以發(fā)現(xiàn),一個頁面中優(yōu)先級最高的其實是服務(wù)端的編碼設(shè)置,如果一旦服務(wù)端設(shè)置了編碼A,那么頁面即以A來解析。
目前Google采用的是這一做法,這樣的傳輸效率會更高,不需要在頭部額外再單獨(dú)申明編碼,但這樣其實也有一定的風(fēng)險,除了需要有一個嚴(yán)謹(jǐn)?shù)木幋a規(guī)范,還需要確保服務(wù)器上的頁面都保持同一編碼,一旦不一致就會造成亂碼,所以目前這一方案在國內(nèi)用的并不多。
其他的,如果外鏈資源設(shè)置了編碼C,那么即以C來解析,無論服務(wù)端和頭部是否申明編碼。
但必須要提醒大家的是:申明的編碼只是告訴瀏覽器相關(guān)的內(nèi)容是以什么方案去解碼,并不是這一部分內(nèi)容就采用了這個編碼。所以大家在coding時的編碼一定要確保和你申明的保持統(tǒng)一,不然就會出現(xiàn)亂碼的問題。
BOM是個神馬
BOM是byte-order mark的縮寫,為Unicode標(biāo)準(zhǔn)為了用來區(qū)分一個文件是UTF-8還是UTF-16或UTF-32編碼方式的記號,又稱字節(jié)序。
UTF-8以單字節(jié)為編碼單元,并沒有字節(jié)序的問題,而UTF-16以兩個字節(jié)為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節(jié)序。例如“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是 “奎”還是“乙”?這是UTF-16文件開頭的BOM就有作用了。
采用Unicode編碼方式的文件如果開頭出現(xiàn)了“FEFF”,“FEFF”在UCS中是不存在的字符,也叫做“ZERO WIDTH NO-BREAK SPACE”,那么就表明這個文件的字節(jié)流是Big-Endian(高字節(jié)在前)的;如果收到“FFFE”,就表明字節(jié)流是Little- Endian(低字節(jié)在前)。
在UTF-8文件中放置BOM主要是微軟的習(xí)慣,BOM其實是為UTF-16和UTF-32準(zhǔn)備的,微軟在UTF-8使用BOM是因為這樣可以把UTF-8和ASCII等編碼明確區(qū)分開,但這樣的文件在Window以外的其他操作系統(tǒng)里會帶來問題。
我們以Window下的文本文件為例:
在保存時可以選擇ANSI、Unicode、Unicode big endian和UTF-8四種編碼方式。
其中ANSI是默認(rèn)的編碼方式,對于英文文件是ASCII編碼,對于簡體中文文件是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會采用Big5碼);
Unicode其實是UTF-16 endian big編碼方式,這個把帶有BOM的小端序UTF-16稱作Unicode而又不詳細(xì)說明,也是微軟的習(xí)慣;
而Unicode big endian則是帶有BOM的大端序編碼方式
目前UTF-16通常用于系統(tǒng)文件的編碼,而UTF-32由于對每個字符都采用四個字節(jié)編碼,所以現(xiàn)在互聯(lián)網(wǎng)中大部分都采用UTF-8來進(jìn)行編碼傳輸。
關(guān)于未來的展望
概述
(圖:中國地區(qū)ALEXA排名前20的站點所采用的編碼占比)
(圖:騰訊互娛所有業(yè)務(wù)所采用的編碼占比)
左圖表明GB2312、GBK與UTF-8編碼三分天下,而右圖顯示騰訊互娛的業(yè)務(wù)大多數(shù)采用了GB2312,零星的采用了其他編碼??偟木褪遣煌淖址幋a方案基本都存在了,而這也與各公司業(yè)務(wù)的歷史原因也有一定的關(guān)系。
當(dāng)我們在項目的最初期時采用了一種非Unicode編碼方案時,隨著業(yè)務(wù)的壯大,積累的頁面越來越多,到后期想去改成Unicode編碼方案,就會擔(dān)心出錯的問題,所以現(xiàn)在大多數(shù)公司都采用了延用初期編碼的方式,如淘寶,騰訊互娛等,以及四大門戶。
擺在眼前的問題
可是,某一天了,我們的網(wǎng)站用戶港澳臺用戶也變多了,我們需要支持繁體怎么辦?
某一天,我們的業(yè)務(wù)拓展到東南亞了,我們需要我們的網(wǎng)站也能支持那些國家的語言怎么辦?
如今,國內(nèi)大多數(shù)公司采用的方案是,為相應(yīng)的環(huán)境單獨(dú)做一套編碼文件,如 http://big5.china.com.cn/ ,又如 http://big5.qidian.com。
再比如,哪一天了,我們的網(wǎng)站需要支持少數(shù)民族的語言怎么辦?
難道像央視這樣切成圖么?
嗯,這一切都只是暫時的方案,但人一旦變得懶起來,就不愿意去改變一些東西,就比如UTF-8。
擁抱國際化標(biāo)準(zhǔn)
一切就等著我們敞開胸懷去擁抱,而不是沉浸在過去的喜悅中。最終的編碼方案決定權(quán)在我們自己手里,改變,只是時間的問題。
本文由企業(yè)網(wǎng)絡(luò)服務(wù)平臺中億智企云網(wǎng)商學(xué)院為你提供,關(guān)于更多相關(guān)資訊,請瀏覽我們的企業(yè)網(wǎng)絡(luò)服務(wù)平臺官網(wǎng)http://17wansf.top,或是撥打我們的全國服務(wù)熱線:400-698-5980!
全國客戶服務(wù)免費(fèi)熱線:15874991942
在線客服:2225973985
每天前10名咨詢有好禮
智企云 版權(quán)所有 ? 2016-2018 湘ICP備11017552號
地址:長沙市高新開發(fā)區(qū)尖山路39號中電軟件園總部大樓6樓
Copyright ? 2015-2024 智企云 All Rights Reserved. 湘ICP備11017552號 技術(shù)支持:中億智企云
湘公網(wǎng)安備43019002000674號 客服熱線:15874991942 公司地址:長沙市高新開發(fā)區(qū)尖山路39號中電軟件園總部大樓6樓