利用今天一天的時間,研究了一下ANSI編碼和Unicode編碼的不同,下面把我的研究成果寫下來,以備
日后參考。
ANSI編碼最常見的應用就是在Windows當中的記事本程序中,當新建一個記事本,默認的保存編碼格式
就是ANSI,ANSI應該算是一種壓縮編碼了,當遇到標準的ASCII字符時,采用單字節(jié)表示,當遇到非標
準的ASCII字符(如中文)時,采用雙字節(jié)表示。
Unicode編碼標準已在近年來的多種新科技當中被加以采用,包含了可擴展置標語言(XML)、Java程
序語言、以及最新的操作系統(tǒng)中。
下面用實驗的方法來進行研究這兩者之間的差別:
首先要準備的軟件有UltraEdit,用于對文本進行比較;其次用于分析網絡字節(jié)序的輔助網站
步入正題,在一個空白的文件夾下創(chuàng)建一個記事本文檔“新建 文本文檔.txt”,在里面輸入“宋體
ABC(回車)”(不包含引號,最后要在ABC后輸入一個回車),保存并關閉該文檔,將此文件選中之后直
接復制、粘貼,在相同的文件夾下就產生了“復件 新建 文本文檔.txt”,再次打開“新建 文本文檔
.txt”,選擇菜單中的“文件”->“另存為”,在另存為對話框中,最下面有“編碼”,選擇Unicode
。保存,選擇替換。
然后打開UltraEdit,在菜單中選擇“文件”->“比較文件”(或直接按快捷鍵Alt+F11),選擇第一個要比較的文件為“新建文本文檔.txt”,選擇第二個要比較的文件為“復件 新建文本文檔.txt”,“比較模式”選擇文件,“二方比較”,“要比較的第一個文件”為“二進制”,“編輯器平鋪”選擇“垂直平鋪”,點擊“比較”,程序自動對這兩個文本文件進行比較,并以16進制的形式顯示,如下圖所示
根據分析,其代表的意義如下圖所示
采用Unicode編碼存儲的文本文檔
采用ANSI編碼存儲的文本文檔
在用Unicode對文字進行編碼時,頭兩個字節(jié)一定是FF FE,這樣用來標識此文檔以Unicode編碼
下面來關注一下內容的編碼部分
中文,作為一種非ASCII字符,不可能只用一個字節(jié)來表示一個漢字,至少需要用兩個字節(jié)來表示,所以,中文是一種雙字節(jié)字符,下圖所示的是在http://bm.kdd.cc/index.asp上查詢到的“宋體”兩個漢字,分別用Unicode編碼和ANSI編碼的十六進制內容:
用Unicode編碼的“宋體”
用ANSI編碼的“宋體”
在Unicode編碼中,“宋”這個漢字的編碼為5B8B,按照二進制的說法,5B是高八位,8B是低八位,然而,對照著前面所標注的結果,用Unicode編碼的文本文件中,先存儲的是8B這個低八位,然后再存儲的5B這個高八位,這就是Windows內部在處理Unicode字符的時候與其他系統(tǒng)(如MacOS)的不同,Windows先處理Unicode字符的低八位,然后再處理高八位;而有的系統(tǒng)是先處理高八位,再處理低八位,這就是為什么在Internet上要規(guī)定“網絡字節(jié)序”。
在ANSI編碼中,完全不存在這個問題,“宋”的ANSI編碼為CB CE,在存儲這些字符的時候也是按照先高八位,后低八位的方式存儲的。
以上討論了中文在Unicode和ANSI編碼中的特點,下面看一下ASCII字符在這兩種編碼中的特點:
在Unicode中,所有字符都是以兩個字節(jié)來存儲的,而ASCII字符僅用一個字節(jié)就可以表示,那么另外一個字節(jié)的內容就會被置為00。采用Unicode會產生的缺點就是:如果一篇文章里全是英文,那么,采用Unicode方式編碼存儲,所占用的存儲空間會大約增加一倍(因為頭部還要多兩個字節(jié)的FFFE標識),但是采用Unicode編碼的好處就是適合同一文檔中采用不同語言的文字,因此Unicode編碼廣泛應用于xml語言和編寫多語言程序。
在本文的第二組圖中,可以看到,采用Unicode編碼的大寫英文字母A,其編碼為0041(之前曾經解釋了Windows在處理Unicode字符的時候先處理低八位,后處理高八位),因為Unicode存儲的任何字符都占用2個字節(jié)的空間,所以在解碼的時候就兩個字節(jié)兩個字節(jié)地取。如果發(fā)現(xiàn)高八位不是00,則認為這兩個字節(jié)表示一個非ASCII字符,反之如果發(fā)現(xiàn)高八位為00,則可知,該字符為ASCII字符,于是取出低八位,再根據ASCII碼表查到對應字符,因為取出的低八位認為表示的是一個ASCII字符,所以字符空間為2的8次方,也就是256個,因此采用Unicode編碼表式的ASCII字符屬于擴展的ASCII字符集。
在第二組圖的ANSI編碼解釋中可以看到,存儲一個大寫英文字母A僅用了一個字節(jié),內容為41。十六進制的41轉換為八位的二進制后應該是 01000001,可以看到,此二進制數的最高位為0,ANSI編碼在存儲ASCII字符時采用的是傳統(tǒng)的ASCII字符集,其字符數量為128,正好2的7次方就是128,因此最高位一定是0。漢字“宋”的ANSI編碼為CBCE,將這兩個字節(jié)的十六進制數轉換為二進制,結果為[11001011][11001110] ,每個字節(jié)的最高位都是1,由此可以推斷在解碼的時候,一次讀取一個字節(jié)的內容,看一下該字節(jié)的最高位是否為1,如果為1,暫存該字節(jié),并讀取下一個字節(jié),新讀取的這個字節(jié)的最高位應該也為1,這樣將兩個字節(jié)合并然后去查詢對應的字符;如果第一次讀到的一個字節(jié)最高位為0,那么就按此字節(jié)的內容直接查詢傳統(tǒng)的ASCII碼表,找到對應的字符。
最后再分析Windows中的回車換行特點。在開始的時候為了準備這個實驗用的文本文檔,在輸入完ABC后又輸入了一個回車。但是通過分析得知,在文本存儲的時候并不是僅存了一個“回車”,還存了一個“換行”,而且是先存儲的“回車”后存儲的“換行”(見ASCII碼表:0D->回車;0A->換行),這與Linux/Unix中的換行方式不同,在Linux/Unix中僅用一個0D(回車)就可以令文本換行。如果將一個在Linux/Unix中編寫的文本文檔直接拷貝到Windows中打開(最簡單的可以在Windows下查看百度首頁的源代碼),就會看到這些文字幾乎都是連著的,沒有換行,那是因為在該文檔中并沒有顯式地存儲0A(換行符),雖然這篇文章在Linux/Unix中看起來很正常。