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