檔案編碼入門 UTF 8和GB

2021-08-31 12:50:43 字數 3955 閱讀 7333

在簡體中文

windows系統中:

1.開啟記事本,輸入「移動」,儲存關閉後重新開啟,顯示的仍然是「移動」兩個字。

2.重新新建乙個文字檔案,輸入「聯通」,儲存關閉後重新開啟,顯示的就不是「聯通」字元了,而是看上去所謂的亂碼。

的確,這就是乙個編碼問題。

字元需要編碼,一套編碼體系就形成了乙個字符集。美國人最開始只創造了乙個字符集,也就是ascii字符集,ascii字符集,長8位,首位為0。後來歐洲國家發現128個字元不夠用,想利用ascii後128位,128位還是滿足不了所有歐洲國家的要求,就對後128個字元進行分片,形成了iso-8859系列字符集,包括iso-8859-1,iso-8859-2等。

計算機來到中國後,又催生了gb2312編碼標準,gb2312沒有包括繁體字,後又擴充套件成為gbk(gb13000),gbk是gb2312的「超集」。gb2312和gbk編碼標準中,儲存方法相容ascii,漢字占用兩個位元組。2023年和2023年又發布了gb18030-2000和gb18030-2005編碼標準,儲存方法中有單位元組、雙位元組和四位元組三種方式對字元編碼進行儲存。平時說的ansi編碼,都是根據不同的國家和地區而不同的標準。在簡體中文系統下,ansi 編碼代表 gbk 編碼,在日文作業系統下,ansi 編碼代表 jis 編碼。 不同 ansi 編碼之間互不相容,當資訊在國際間交流時,無法將屬於兩種語言的文字,儲存在同一段 ansi 編碼的文字中。

歷史介紹省略數百字。。。

unicode基於通用字符集(universal character set)的標準來發展,是國際組織制定的可以容納世界上所有文字和符號的字元編碼方案。unicode用數字0-0x10ffff來對映這些字元,最多可以容納1114112個字元,或者說有1114112個碼位。碼位就是可以分配給字元的數字。

(ucs-2用兩個位元組編碼, ucs-4用4個位元組編碼。ucs-4根據最高位為0的最高位元組分成2^7=128個group。每個group再根據次高位元組分為256個平面(plane)。每個平面根據第3個位元組分為256行 (row),每行有256個碼位(cell)。group 0的平面0被稱作bmp(basic multilingual plane)。將ucs-4的bmp去掉前面的兩個零位元組就得到了ucs-2。每個平面有2^16=65536個碼位。)

unicode和gb***是兩套不同的編碼標準,字元的碼位不相同,如果需要轉換,必須要同時知道乙個字元在兩個編碼中的碼位。

unicode是編碼標準,並沒有規定字元的儲存方式。utf-8、utf-16、utf-32都是將unicode標準中的碼位轉換到具體儲存資料的方案。總之,任何乙個編碼標準和具體的字元儲存方案是分離的,只要儲存後的編碼還能對映到原始的編碼標準中的碼位。

為什麼不直接用unicode的ucs-2碼位來直接當作字元儲存的資料編碼呢,一是為了考慮和ascii的相容性,二是對屬於ascii的字元用unicode編碼太占用空間。utf-8就是在這樣的情況下誕生了。utf-8只是一種編碼的儲存方案,從乙個字元的utf-8編碼可以找到唯一對應的unicode碼位。

簡單介紹下utf-8,utf-8以位元組為單位對unicode進行編碼。從unicode到utf-8的編碼方式如下:

unicode編碼(16進製制)

║ utf-8 位元組流(二進位制)

000000 - 00007f

║ 0******x

000080 - 0007ff

║ 110***xx 10******

000800 - 00ffff

║ 1110***x 10****** 10******

010000 - 10ffff

║ 11110*** 10****** 10****** 10******

utf-8的特點是對不同範圍的字元使用不同長度的編碼。對於0x00-0x7f之間的字元,utf-8編碼與ascii編碼完全相同。utf-8編碼的最大長度是4個位元組。從上表可以看出,4位元組模板有21個x,即可以容納21位二進位制數字。unicode的最大碼位0x10ffff也只有21位。

例:「漢」字的unicode編碼是0x6c49。0x6c49在0x0800-0xffff之間,使用用3位元組模板了:1110***x 10****** 10******。將0x6c49寫成二進位制是:0110 1100 0100 1001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即e6 b1 89。

判斷乙個文字編碼是否是utf-8編碼的最簡單的正則: /

^([\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]|[\xf0-\xf7][\x80-\xbf])+$/

上述正則並不是100%能夠判斷正確的。事實上也沒有100%正確的方法。乙個bad case就是文章開頭提到的「聯通」例子,「聯通」的gbk編碼是c1 aa cd a8,剛好符合了上述的正規表示式,被windows記事本認為是utf-8來編碼了。

聯通的bad case還不是最bad的,假如c1 aa cd a8是utf-8編碼,c1 aa對應到unicode的十六進製制表示是6a(字元j),只需要乙個位元組就可以表示了。所以c1 aa不是乙個規範的utf-8編碼,雖然c1 aa可以通過簡單的正規表示式驗證。

下面是乙個更bad的case,記事本輸入「傘」,關閉後再開啟,就變成拉丁字元ɡ了,對於這樣乙個文字檔案,如果不額外告訴程式是什麼編碼的,程式當utf-8和當gbk來處理都不是程式的錯了。

那麼哪些漢字會引起當作utf-8來誤讀的情況呢?根據正規表示式和gbk的編碼情況(全國資訊科技標準化技術委員會漢字內碼擴充套件規範(gbk)碼:

),在[\xc0-\xdf][\x

80-\xbf]之間的gbk編碼的漢字都可能會有問題,只要gbk編碼的

文字檔案中的字元都是落在這個範圍內(包括有任意的其它ascii字元的情況,比如「傘1」也會被當作utf-8來處理),都會出現編碼難以或者不能判斷的情況。

utf-8的編碼就介紹到這兒,沒有什麼準確判斷utf-8編碼的方法,isutf8encode這樣的函式如果返回值是二值的,都是有例外的。到可以寫個判斷肯定不是utf-8編碼的方法。

bom——byte order mark,中文名譯作「位元組順序標記」。在ucs 編碼中有乙個叫做 "zero width no-break space" ,中文譯名作「零寬無間斷間隔」的字元,它的編碼是usc編碼是feff。而fffe 在 ucs 中是不存在的字元,所以不應該出現在實際傳輸中。ucs 規範建議我們在傳輸位元組流前,先傳輸字元 "zero width no-break space"。這樣如果接收者收到 feff,就表明這個位元組流是 big-endian 的;如果收到fffe,就表明這個位元組流是 little- endian 的。因此字元 "zero width no-break space" (「零寬無間斷間隔」)又被稱作 bom。

utf-8 不需要 bom 來表明位元組順序,但可以用 bom 來表明編碼方式(不知道是不是ms幹的)。字元 "zero width no-break space" 的 utf-8 編碼是 ef bb bf。所以如果接收者收到以 ef bb bf 開頭的位元組流,就知道這是 utf-8編碼了。windows 就是使用 bom 來標記文字檔案的編碼方式的。所以utf-8一般有兩種,乙個是utf-8 with bom,乙個是utf-8 without bom。linux下的非常多的程式都是不認utf-8 with bom的,另外php也是不認的,只要有bom的utf-8,php(最新版本是否支援bom未驗證)就會出錯。

不過用bom也會有bad case,「鍩胯創」三個字在記事本中以gbk儲存後再開啟就變成了utf-8的「貼」。不要在utf-8中儲存bom頭。如果在程式的輸出中看到字元「鍩」就要格外注意,很有可能是utf-8 with bom的編碼被當作gbk的來處理了。

個人認為gbk的主要優勢在於web頁面和減少磁碟io,gbk能夠節省實實在在的頻寬,假設乙個web請求可以省下100個位元組,那麼100萬/秒的訪問下,能夠節省100mb/s的頻寬了。也許伺服器可以支撐更大規模的請求訪問,處理更多的資料,但是頻寬不見得夠用。

對於輸入輸出中有字串的,最好都明確告知編碼。程式自身內部的編碼可以統一,而在輸入輸出的時候按要求進行轉碼。

參考文獻

GB2312和utf8編碼轉換

經常的寫中文出現亂碼,用編碼器翻譯在粘上去,有的還翻譯不過去。還是用翻譯函式吧 gb2312轉換成utf 8 utf iconv gb2312 utf 8 request keyword 將字串utf 8碼轉換為gb2312碼 str iconv utf 8 gb2312 translit str ...

網頁設計中 utf 8和gb2312編碼

1 utf 8 utf 8 8 bit unicode transformation format 是一種針對unicode的可變長度字元編碼,又稱萬國碼。由ken thompson於1992年建立。現在已經標準化為rfc 3629。utf 8用1到4個位元組編碼unicode字元。用在網頁上可以同...

網頁設計中 utf 8和gb2312編碼

1 utf 8 utf 8 8 bit unicode transformation format 是一種針對unicode的可變長度字元編碼,又稱萬國碼。由ken thompson於1992年建立。現在已經標準化為rfc 3629。utf 8用1到4個位元組編碼unicode字元。用在網頁上可以同...