因?yàn)殡娔X是windows 7系統(tǒng),開(kāi)發(fā)環(huán)境又在linux,經(jīng)常在linux碰到亂碼問(wèn)題,很是痛苦,于是決定好好了解編碼的來(lái)龍氣脈,并分享個(gè)各位,免得出現(xiàn)亂碼時(shí)不知所措。
是否存在文件編碼
在講解字符編碼之前,我們需先明確文件本身沒(méi)有編碼一說(shuō),只有文字才有編碼的概念,我們通常說(shuō)某個(gè)文件是什么編碼,通常是指文件里字符的編碼。
vim為什么會(huì)出現(xiàn)亂碼
我在linux下一般使用vim進(jìn)行文件編輯,發(fā)現(xiàn)經(jīng)常會(huì)碰到亂碼的情況,那么為什么會(huì)出現(xiàn)亂碼呢? 首先我們了解下vim編碼方面的基礎(chǔ)知識(shí),關(guān)于編碼方面vim存在3個(gè)變量:
1.encoding: Vim 內(nèi)部使用的字符編碼方式,包括 Vim 的 buffer (緩沖區(qū))、菜單文本、消息文本等。默認(rèn)是根據(jù)你的locale選擇.用戶(hù)手冊(cè)上建議只在 .vimrc 中改變它的值,事實(shí)上似乎也只有在.vimrc 中改變它的值才有意義。你可以用另外一種編碼來(lái)編輯和保存文件,如你的vim的encoding為utf-8,所編輯的文件采用cp936編碼,vim會(huì)自動(dòng)將讀入的文件轉(zhuǎn)成utf-8(vim的能讀懂的方式),而當(dāng)你寫(xiě)入文件時(shí),又會(huì)自動(dòng)轉(zhuǎn)回成cp936(文件的保存編碼).
2.fileencoding: Vim 中當(dāng)前編輯的文件的字符編碼方式,Vim 保存文件時(shí)也會(huì)將文件保存為這種字符編碼方式 (不管是否新文件都如此)。
3.termencoding: Vim 所工作的終端 (或者 Windows 的 Console 窗口) 的字符編碼方式。如果vim所在的term與vim編碼相同,則無(wú)需設(shè)置。如其不然,你可以用vim的termencoding選項(xiàng)將自動(dòng)轉(zhuǎn)換成term的編碼.
當(dāng)這三個(gè)變量的編碼出現(xiàn)問(wèn)題時(shí)就會(huì)出現(xiàn)亂碼:
1.encoding不是utf-8編碼:如果encoding不是utf-8編碼,其他字符可能無(wú)法轉(zhuǎn)為 Encoding的指定編碼。如:如果encoding是gbk編碼,而文件內(nèi)容采用big5編碼的,其就無(wú)法轉(zhuǎn)換為gbk編碼。
2.fileencoding不對(duì):Fileencoding編碼是vim的讀取文件內(nèi)容時(shí)使用的編碼,如果其編碼與文件字符編碼不同,必然會(huì)出現(xiàn)亂碼。Fileencoding編碼一般由vim自動(dòng)檢測(cè),可以使用fileencodings設(shè)置,Vim自動(dòng)探測(cè)fileencoding的順序列表。不過(guò)vim有時(shí)候會(huì)檢測(cè)錯(cuò)誤,就會(huì)出現(xiàn)亂碼了。
3.termencoding編碼不對(duì):我們登錄服務(wù)器一般采用遠(yuǎn)程登錄,這就涉及終端編碼問(wèn)題,我經(jīng)常碰到因?yàn)榻K端編碼不對(duì)導(dǎo)致亂碼的。如:SecureCRT設(shè)置為utf-8編碼,而vim的termencoding卻為gbk,就出現(xiàn)亂碼了。
字符編碼介紹
說(shuō)了那么多,到底字符編碼是什么玩意呢?
字符(Character)是文字與符號(hào)的總稱(chēng),包括文字、圖形符號(hào)、數(shù)學(xué)符號(hào)等,一組抽象字符的集合就是字符集(Charset)。 字符集常常和一種具體的語(yǔ)言文字對(duì)應(yīng)起來(lái),該文字中的所有字符或者大部分常用字符就構(gòu)成了該文字的字符集,比如英文字符集,漢字字符集。 計(jì)算機(jī)要處理各種字符,就需要將字符和二進(jìn)制內(nèi)碼對(duì)應(yīng)起來(lái),這種對(duì)應(yīng)關(guān)系就是字符編碼(Encoding)。 制定編碼首先要確定字符集,并將字符集內(nèi)的字符排序,然后和二進(jìn)制數(shù)字對(duì)應(yīng)起來(lái)。根據(jù)字符集內(nèi)字符的多少,會(huì)確定用幾個(gè)字節(jié)來(lái)編碼。
字符集和編碼的區(qū)別:
字符集字符的集合,不一定適合計(jì)算機(jī)存儲(chǔ)、網(wǎng)絡(luò)傳送、處理,有時(shí)須經(jīng)編碼(encode)后才能應(yīng)用。如Unicode字符集可依不同需要以UTF-8、UTF-16、UTF-32等方式編碼。
字符編碼的發(fā)展
字符編碼大概分為三個(gè)發(fā)展階段。
ASCII編碼:ASCII(American Standard Code for Information Interchange,美國(guó)信息互換標(biāo)準(zhǔn)代碼)是基于拉丁字母的一套電腦編碼系統(tǒng)。 因?yàn)橛?jì)算機(jī)起源于美國(guó),為表示英文字符,他們制定了ASCII編碼,ASCII編碼使用7位二進(jìn)制來(lái)表示字符,高位用來(lái)做奇偶校驗(yàn),0×20以下的字節(jié)狀態(tài)稱(chēng)為”控制碼”,同時(shí)包括標(biāo)點(diǎn)符號(hào)、數(shù)字等,當(dāng)時(shí)人們覺(jué)得已經(jīng)夠用了。
多種編碼并存:但隨著計(jì)算機(jī)的廣泛應(yīng)用,別的國(guó)家也開(kāi)始使用計(jì)算機(jī),但是很多國(guó)家用的不是英文,他們的字母里有許多是ASCII里沒(méi)有的,為了可以在計(jì)算機(jī)保存他們的文字,他們決定采用127號(hào)之后的空位來(lái)表示這些新的字母、符號(hào),還加入了很多畫(huà)表格時(shí)需要用下到的橫線(xiàn)、豎線(xiàn)、交叉等形狀,一直把序號(hào)編到了最后一個(gè)狀態(tài)255。從128到255這一頁(yè)的字符集被稱(chēng)”擴(kuò)展字符集”。最優(yōu)秀的擴(kuò)展方案是ISO 8859-1,通常稱(chēng)之為L(zhǎng)atin-1,Latin-1包括了足夠的附加字符集來(lái)寫(xiě)基本的西歐語(yǔ)言。
后來(lái)其他國(guó)家也開(kāi)始使用計(jì)算機(jī),為了表達(dá)自己國(guó)家的文字,不同的國(guó)家和地區(qū)制定了不同的標(biāo)準(zhǔn),產(chǎn)生了GB2312,BIG5,JIS等各自的編碼標(biāo)準(zhǔn)。通常使用0×80~xFF范圍的2個(gè)字節(jié)來(lái)表示1個(gè)字符。比如:漢字 ‘中' 在中文操作系統(tǒng)中,使用 [0xD6,0xD0]這兩個(gè)字節(jié)存儲(chǔ)。 這些使用2個(gè)字節(jié)來(lái)代表一個(gè)字符的延伸編碼方式,稱(chēng)為 ANSI 編碼。
在簡(jiǎn)體中文系統(tǒng)下,ANSI 編碼代表 GB2312 編碼,在日文操作系統(tǒng)下,ANSI 編碼代表 JIS 編碼。 不同 ANSI 編碼之間互不兼容,當(dāng)信息在國(guó)際間交流時(shí),無(wú)法將屬于兩種語(yǔ)言的文字,存儲(chǔ)在同一段 ANSI 編碼的文本中。
Unicode編碼 由于不同國(guó)家的ANSI編碼互不兼容,為了使國(guó)際間信息交流更加方便,國(guó)際組織制定了UNICODE字符集,為各種語(yǔ)言中的每一個(gè)字符設(shè)定了統(tǒng)一并且唯一的數(shù)字編號(hào),以滿(mǎn)足跨語(yǔ)言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求。 UNICODE開(kāi)始制訂時(shí),計(jì)算機(jī)的存儲(chǔ)器容量極大地發(fā)展了,空間再也不成為問(wèn)題了。于是ISO就直接規(guī)定必須用兩個(gè)字節(jié),也就是16位來(lái)統(tǒng)一表示所有的字符,對(duì)于ascii里的那些“半角”字符,UNICODE保持其原編碼不變,只是將其長(zhǎng)度由原來(lái)的8位擴(kuò)展為16位,而其他文化和語(yǔ)言的字符則全部重新統(tǒng)一編碼。由于”半角”英文符號(hào)只需要用到低8位,所以其高8位永遠(yuǎn)是0,因此這種大氣的方案在保存英文文本時(shí)會(huì)多浪費(fèi)一倍的空間。
但是UNICODE來(lái)到時(shí),一起到來(lái)的還有計(jì)算機(jī)網(wǎng)絡(luò)的興起,UNICODE如何在網(wǎng)絡(luò)上傳輸也是一個(gè)必須考慮的問(wèn)題,于是面向傳輸?shù)谋奤TF(UCS Transfer Format)標(biāo)準(zhǔn)出現(xiàn)了,顧名思義,UTF8就是每次8個(gè)位傳輸數(shù)據(jù),而UTF16就是每次16個(gè)位,只不過(guò)為了傳輸時(shí)的可靠性,從UNICODE到UTF時(shí)并不是直接的對(duì)應(yīng),而是要過(guò)一些算法和規(guī)則來(lái)轉(zhuǎn)換。
學(xué)過(guò)計(jì)算機(jī)網(wǎng)絡(luò)的童鞋都知道,在網(wǎng)絡(luò)里傳遞信息時(shí)有一個(gè)很重要的問(wèn)題,就是對(duì)于數(shù)據(jù)高低位的解讀方式,一些計(jì)算機(jī)是采用低位先發(fā)送的方法,例如我們PC機(jī)采用的INTEL架構(gòu);而另一些是采用高位先發(fā)送的方式。在網(wǎng)絡(luò)中交換數(shù)據(jù)時(shí),為了核對(duì)雙方對(duì)于高低位的認(rèn)識(shí)是否是一致的,采用了一種很簡(jiǎn)便的方法,就是在文本流的開(kāi)始時(shí)向?qū)Ψ桨l(fā)送一個(gè)標(biāo)志符——如果之后的文本是高位先發(fā)送,那就發(fā)送”FEFF”,反之,則發(fā)送”FFFE”。(IP/TCP協(xié)議規(guī)定網(wǎng)絡(luò)字節(jié)序使用大端法)
因?yàn)閁TF-8編碼兼容之前的ASCII編碼,而且有利于傳輸,其得到了非常廣泛的應(yīng)用。
從UNICODE到UTF8的轉(zhuǎn)換規(guī)則:
復(fù)制代碼 代碼如下:
Unicode UTF-8
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
漢字ANSI編碼發(fā)展
GB2312:為了表示漢字,我們國(guó)家首先發(fā)明了GB2312 編碼,GB2312 編碼規(guī)定一個(gè)小于127的字符的意義與原來(lái)相同,但兩個(gè)大于127的字符連在一起時(shí),就表示一個(gè)漢字,前面的一個(gè)字節(jié)(他稱(chēng)之為高字節(jié))從0xA1用到0xF7,后面一個(gè)字節(jié)(低字節(jié))從0xA1到0xFE,這樣我們就可以組合出大約7000多個(gè)簡(jiǎn)體漢字了。在這些編碼里,我們還把數(shù)學(xué)符號(hào)、羅馬希臘的字母、日文的假名們都編進(jìn)去了,連在 ASCII 里本來(lái)就有的數(shù)字、標(biāo)點(diǎn)、字母都統(tǒng)統(tǒng)重新編了兩個(gè)字節(jié)長(zhǎng)的編碼,這就是常說(shuō)的”全角”字符,而原來(lái)在127號(hào)以下的那些就叫”半角”字符了。
GBK 后來(lái)發(fā)現(xiàn)很多偏僻字和少數(shù)名族的語(yǔ)言還是沒(méi)辦法編碼進(jìn)來(lái),為了表示這些字符,于是干脆不再要求低字節(jié)一定是127號(hào)之后的內(nèi)碼,只要第一個(gè)字節(jié)是大于127就固定表示這是一個(gè)漢字的開(kāi)始,不管后面跟的是不是擴(kuò)展字符集里的內(nèi)容。結(jié)果擴(kuò)展之后的編碼方案被稱(chēng)為 GBK 標(biāo)準(zhǔn),GBK包括了GB2312的所有內(nèi)容,同時(shí)又增加了近20000個(gè)新的漢字(包括繁體字)和符號(hào)。
GB18030 后來(lái)少數(shù)民族也要用電腦了,于是我們?cè)贁U(kuò)展,又加了幾千個(gè)新的少數(shù)民族的字,GBK擴(kuò)成了GB18030。從此之后,中華民族的文化就可以在計(jì)算機(jī)時(shí)代中傳承了。
BOM介紹
1.BOM的來(lái)歷: 為了識(shí)別 Unicode 文件,Microsoft 建議所有的 Unicode 文件應(yīng)該以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符開(kāi)頭。這作為一個(gè)“特征符”或“字節(jié)順序標(biāo)記(byte-order mark,BOM)”來(lái)識(shí)別文件中使用的編碼和字節(jié)順序。
2.不同的系統(tǒng)對(duì)BOM的支持:因?yàn)橐恍┫到y(tǒng)或程序不支持BOM,因此帶有BOM的Unicode文件有時(shí)會(huì)帶來(lái)一些問(wèn)題。
①JDK1.5以及之前的Reader都不能處理帶有BOM的UTF-8編碼的文件,解析這種格式的xml文件時(shí),會(huì)拋出異常:Content is not allowed in prolog。
②Linux/UNIX 并沒(méi)有使用 BOM,因?yàn)樗鼤?huì)破壞現(xiàn)有的 ASCII 文件的語(yǔ)法約定。
③不同的編輯工具對(duì)BOM的處理也各不相同。使用Windows自帶的記事本將文件保存為UTF-8編碼的時(shí)候,記事本會(huì)自動(dòng)在文件開(kāi)頭插入BOM(雖然BOM對(duì)UTF-8來(lái)說(shuō)并不是必須的)。而其它很多編輯器用不用BOM是可以選擇的。UTF-8、UTF-16都是如此。
3.BOM與XML:XML解析讀取XML文檔時(shí),W3C定義了3條規(guī)則:
①如果文檔中有BOM,就定義了文件編碼;
②如果文檔中沒(méi)有BOM,就查看XML聲明中的編碼屬性;
③如果上述兩者都沒(méi)有,就假定XML文檔采用UTF-8編碼。
決定文本的字符集與編碼
軟件通常有三種途徑來(lái)決定文本的字符集和編碼:
1.檢測(cè)BOM
對(duì)于Unicode文本最標(biāo)準(zhǔn)的途徑是檢測(cè)文本最開(kāi)頭的幾個(gè)字節(jié)。
復(fù)制代碼 代碼如下:
開(kāi)頭字節(jié) Charset/encoding
EF BB BF UTF-8
FE FF UTF-16/UCS-2, little endian(UTF-16LE)
FF FE UTF-16/UCS-2, big endian(UTF-16BE)
FF FE 00 00 UTF-32/UCS-4, little endian.
00 00 FE FF UTF-32/UCS-4, big-endia
2.用戶(hù)選擇: 采取一種比較安全的方式來(lái)決定字符集及其編碼,那就是彈出一個(gè)對(duì)話(huà)框來(lái)請(qǐng)示用戶(hù)。
3.采取“猜”的方法: 如果軟件不想麻煩用戶(hù),或者它不方便向用戶(hù)請(qǐng)示,那它只能采取自己“猜”的方法,軟件可以根據(jù)整個(gè)文本的特征來(lái)猜測(cè)它可能屬于哪個(gè)charset,這就很可能不準(zhǔn)了。使用記事本打開(kāi)那個(gè)“聯(lián)通”文件就屬于這種情況。(把原本屬于ANSI編碼的文件當(dāng)成UTF-8處理。
記事本的幾種編碼介紹
1.ANSI編碼:記事本默認(rèn)保存的編碼格式是:ANSI,即本地操作系統(tǒng)默認(rèn)的內(nèi)碼,簡(jiǎn)體中文一般為GB2312。這個(gè)怎么驗(yàn)證呢?用記事本保存后,使用EmEditor、EditPlus和UltraEdit之類(lèi)的文本編輯器打開(kāi)。推薦使用EmEditor,打開(kāi)后,在又下角會(huì)顯示編碼:GB2312。
2.Unicode編碼:用記事本另存為時(shí),編碼選擇“Unicode”,用EmEditor打開(kāi)該文件,發(fā)現(xiàn)編碼格式是:UTF-16LE+BOM(有簽名)。用十六進(jìn)制方式查看,發(fā)現(xiàn)開(kāi)頭兩字節(jié)為:FF FE。這就是BOM。
3.Unicode big endian 用記事本另存為時(shí),編碼選擇“Unicode”,用EmEditor打開(kāi)該文件,發(fā)現(xiàn)編碼格式是:UTF-16BE+BOM(有簽名)。用十六進(jìn)制方式查看,發(fā)現(xiàn)開(kāi)頭兩字節(jié)為:FE FF。這就是BOM。
4.UTF-8 :用記事本另存為時(shí),編碼選擇“UTF-8”,用EmEditor打開(kāi)該文件,發(fā)現(xiàn)編碼格式是:UTF-8(有簽名)。用十六進(jìn)制方式查看,發(fā)現(xiàn)開(kāi)頭三個(gè)字節(jié)為:EF BB BF。這就是BOM。
您可能感興趣的文章:- UTF-8 Unicode Ansi 漢字GB2321幾種編碼轉(zhuǎn)換程序
- php utf-8轉(zhuǎn)unicode的函數(shù)
- 常用字符集編碼詳解(ASCII GB2312 GBK GB18030 unicode UTF-8)
- unicode utf-8 gb18030 gb2312 gbk各種編碼對(duì)比
- VBS實(shí)現(xiàn)GB2312,UTF-8,Unicode,BIG5編碼轉(zhuǎn)換工具
- 戲說(shuō)編碼發(fā)展史