最近遇到一件事情,一個介面能夠接收傳入編碼可能是utf-8,gbk 兩種。 做過編碼方面轉換的同學應該知道的,是什麼編碼不會在字串裡面有什麼標記位的。不過utf-8編碼有特殊性,因此可以通過Regex來檢查。只要發現是utf-8編碼。就轉換,不是utf-8就當gbk處理。 編碼一些常見問題可以查看:由web程式出現亂碼開始挖掘(Bom頭、字元集與亂碼)
知道這個原理,馬上領任務,開始工作。 想到php版本有個mbstring模組可以進行編碼檢測轉換:
php//當前編碼是gbk$str="中國";$aStrList=array($str,iconv('gbk','utf-8',$str));foreach ($aStrList as $v){echo mb_convert_encoding($v,'gbk','utf-8,gbk'),"\r\n";}
?
運行結果:
?
兩個不同編碼的“中國”,用一個函數mb_convert_encoding就可以自動轉換成gbk編碼。首頁,嘗試用utf-8解碼,如果出現問題,就會用gbk轉碼。看來問題解決了,哈哈,可以交差了……
?
- 問題:
發布後,平靜了幾天,突然接到反饋:有中文:”袁小”解碼出錯。⊙﹏⊙b汗 …… ,想……(難道php內建檢測模組有問題,或是我哪裡欠缺……)
⊙﹏⊙b汗…… 看來果然有問題,查詢手冊:mbstring 模組編碼檢查,只是識別字串部分編碼,發現與某個字元集匹配上,就認為它屬於那種編碼。 這不屬於它的bug,因為字串本身沒有編碼資訊標識,沒有那個語言能夠完全檢測通過。
?
- 問題:
能不能自己寫一個檢查Regex看下到底怎麼樣呢?要寫Regex,首先須瞭解utf8編碼規範,查看:http://zh.wikipedia.org/zh/UTF-8?
目前編碼集合只有這樣6個維度:php得到維度代碼
php//得到utf8字編碼各個維度範圍 echo base_convert('1111111',2,16),"\r\n";//維度1echo base_convert('10000000',2,16),base_convert('10111111',2,16),"\r\n";echo base_convert('11000000',2,16),base_convert('11011111',2,16),"\r\n";//維度2echo base_convert('11100000',2,16),base_convert('11101111',2,16),"\r\n";//維度3echo base_convert('11110000',2,16),base_convert('11110111',2,16),"\r\n";//維度4echo base_convert('11111000',2,16),base_convert('11111011',2,16),"\r\n";//維度5echo base_convert('11111100',2,16),base_convert('11111101',2,16),"\r\n";//維度6
運行結果:
- 通過上面6個維度得到得到對應的Regex:
[\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5}
以上分別是各個維度範圍
php//當前編碼是gbk$str="袁";echo urlencode($str);echo is_utf8($str);function is_utf8($str){///utf8編碼正則檢測函數///copyright qq:8292669 http://www.cnblogs.com/chengmo$re='/^([\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})+$/';return preg_match($re,$str);}
上面執行結果返回為1,然後”袁“本身應該是gbk編碼。看來上面函數還是不能徹底檢查utf8編碼。分析原因,從上面正則可以看到,utf8的6個維度對應位元組長度從1-6位元組。 而gbk是1-2個位元組。因此他們之間會在1-2個位元組長度地方檢查出現重合。1個位元組的時候gbk與utf8的 編碼與字元對應關係都一樣,但是2個位元組時候,對應編碼與字元各不相同。
?
通過查詢gbk編碼錶:http://www.knowsky.com/resource/gb2312tbl.htm 進一步確認,範圍會在:
[c0-df][a0-bf] 之內漢字都會有問題了。 如果純這個範圍的漢字組合為字串就會出現判斷不了情況。如果它與其它範圍字元組合都可以正確的判斷出來。
?
GBK與UTF8字元集重疊對應的字元是:(gbk編碼錶)
?
?
| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |