[转]PHP程序中的汉字编码探讨
?
需求:內容按照【UNICODE使用Big Endian 字節順序】編碼后,需要轉成16進制HEX字符串
UNICODE使用Big Endian 字節順序? ? -??UCS-2BE
轉碼如下:
$content=strtoupper(bin2hex(iconv('utf-8','UCS-2BE',$content)));?
?
最近在做一個百度詞典的采集,http://dict.baidu.com,發現了一個可以值得探討的一個問題,漢字的編碼問題。首先,我們輸入一個漢字詞語進行搜索,比如,我們,URL上的地址變成http://dict.baidu.com/s?wd=%CE%D2%C3%C7,前面的http://dict.baidu.com/s?wd=就不用管了,都知道是什么意思,我們關注一下后面“%CE%D2%C3%C7”這幾個東西。顯然是詞語“我們”這個的漢字編碼。我們知道PHP有個函數urlencode,可以把漢字轉換為類似那樣行事的。,得到結果為:%E6%88%91%E4%BB%AC。
顯然,不是%CE%D2%C3%C7這種格式的。是不是進制的問題呢?還是漢字編碼的問題(UTF-8或者GB2312)。我們做一下實驗。
我們先進行轉碼:
| 1 2 3 4 5 6 7 | <?php ? ??$str?=?'我們'; ? ??//iconv('utf-8','cp936',$str); ? ??//echo urlencode($str); ? ??iconv('cp936','utf-8',$str); ? ??echo?urlencode($str); ?> |
發現輸出結果都為:%E6%88%91%E4%BB%AC,因為我測試的頁面為utf-8的頁面。所以結果一樣。當頁面為GBK或者GB2312的時候結果為:%CE%D2%C3%C7,這樣,就和百度上的那個編碼一致了。現在我們主要討論頁面編碼為UTF8的時候,怎么得到正確的編碼。
漢字的編碼究竟是如何做的。我們知道,國內大部分都是GBK編碼的,我們知道,GBK編碼中一個漢字由二個字符組成,獲取漢字字符串的方法如下:
| 1 2 3 4 5 6 7 8 9 10 11 | <?php ? ??$string?=?"我們";? ? ??$length?=?strlen($string);? ? ??for($i=0;$i<$length;$i++){? ? ? ? ??if(ord($string[$i])>127){? ? ? ? ??$result[]?=??ord($string[$i]).' '.ord($string[++$i]);? ? ??}? ? ??}? ? ??var_dump($result);? ? ?? ?> |
由于一個漢字為兩個字符組成,通過ord()函數獲取字符的ASCII值如果大于127時,就可以確定當前字符為一個漢字的前半部分,還需要獲取漢字的后半部分。當然,這種判斷的方法要結合具體的開發環境,如果存在ASCII值大于127的單個字符,這種方法判斷顯然就不正確。得到結果為一個數組:
GBK編碼的頁面結果:
| 1 2 3 4 5 6 | array(2)?{ ??[0]=> ? string(7)?"206 210" ??[1]=> ? string(7)?"195 199" } |
UTF-8的頁面結果:
| 1 2 3 4 5 6 7 8 | array(3)?{ ??[0]=> ? string(7)?"230 136" ??[1]=> ? string(7)?"145 228" ??[2]=> ? string(7)?"187 172" } |
GB2312的頁面結果:
| 1 2 3 4 5 6 | array(2)?{ ??[0]=> ? string(7)?"206 210" ??[1]=> ? string(7)?"195 199" } |
從以上結果可以看出,如果頁面編碼為國標編碼的時候,一個漢字是由兩個字節組成。而頁面編碼為UTF8的時候,漢字是由三個字節組成的。但是進制都是十進制的,而我們需要的是十六進制的。那么怎么把十進制的漢字編碼轉換為十六進制呢?
可以采用以下辦法,php由幾個內建函數可以直接轉換進制,decbin(),十進制轉換為二進制;dechex(),十進制轉換為十六進制;decoct(), 十進制轉換為八進制。
| 1 2 3 4 5 6 7 | <?php? foreach($result?as?$v){? ? ??$dec?=?explode(" ",$v);? ? ??$strings[]?=??dechex($dec[0])." ".dechex($dec[1]);? }? var_dump($strings);? ?> |
UTF8下得到結果為:
| 1 2 3 4 5 6 7 8 | array(3)?{ ??[0]=> ? string(5)?"e6 88" ??[1]=> ? string(5)?"91 e4" ??[2]=> ? string(5)?"bb ac" } |
看到沒,成了十六進制了,同理,轉換二進制或者八進制只需將dechex函數換成decbin或者decoct就可以了。
現在我們明白漢字編碼和轉換進制問題了。
接著我們的問題繼續,在UTF8頁面上實現轉換UTF8漢字為十六進制的GBK漢字編碼。
首先學習兩個函數:strtoupper() 函數把字符串轉換為大寫;base_convert() 函數在任意進制之間轉換數字;iconv() 函數,實現各種字符集間的轉換。mb_detect_encoding() 函數,判斷漢字編碼。
以上是分步進行轉換,先得到漢字編碼的十進制編碼,然后我們用進制轉換函數得到我們想要的漢字編碼。下面我們依然這樣做。
因為我們的頁面是UTF8的頁面。所以,我們先得到漢字的十進制編碼,當然是UTF8下的編碼,然后轉成UTF8的十六進制編碼。然后使用iconv函數進行字符集轉換就了。廢話少說,看代碼:
| 1 2 3 4 5 6 7 8 9 10 11 12 | <?php function?convertStr($str)?{ ? ??$strlength?=?strlen($str); ? ??$cstr?=?''; ? ??for($i?=?0;?$i?<?$strlength;?$i++)?{ ? ? ? ??$cstr?.=?"%".strtoupper(base_convert(ord($str{$i}),?10,?16)); ? ??} ? ??return?$cstr; } $contents?=?($contentscharset?=?mb_detect_encoding($s,?"ASCII, UTF-8, GB2312, GBK"))?==?"GB2312"???$s?:?iconv($contentscharset,?"CP936",?$s); $w?=?convertStr($contents); ?> |
現在$w就是我們想要的十進制GBK下的漢字編碼了了。
convertStr()函數,把漢字以16進制輸出。首先判斷漢字編碼如果是UTF8則由UTF8轉換成GBK的。然后執行convertStr()函數,完成進制轉換。得到結果為:%CE%D2%C3%C7,這樣,我們就得到了這個UTF8下的GBK漢字編碼了。
?
<?php
//測試時文件的編碼方式要是UTF8
$str='中文a字1符';
echo strlen($str).'<br>';//14
echo mb_strlen($str,'utf8').'<br>';//6
echo mb_strlen($str,'gbk').'<br>';//8
echo mb_strlen($str,'gb2312').'<br>';//10
/*
結果分析:在strlen計算時,對待一個UTF8的中文字符是3個長度,所以“中文a字1符”長度是3*4+2=14
在mb_strlen計算時,選定內碼為UTF8,則會將一個中文字符當作長度1來計算,所以“中文a字1符”長度是6?
*/
//利用這兩個函數則可以聯合計算出一個中英文混排的串的占位是多少(一個中文字符的占位是2,英文字符是1)
echo (strlen($str) + mb_strlen($str,'UTF8')) / 2;?
//例如 “中文a字1符” 的strlen($str)值是14,mb_strlen($str)值是6,則可以計算出“中文a字1符”的占位是10.?
echo mb_internal_encoding();
PHP內置的字符串長度函數strlen無法正確處理中文字符串,它得 到的只是字符串所占的字節數。對于GB2312的中文編碼,strlen得到的值是漢字個數的2倍,而對于UTF-8編碼的中文,就是3倍的差異了(在 UTF-8編碼下,一個漢字占3個字節)。
采用mb_strlen函數可以較好地解決這個問題。mb_strlen的用法和 strlen類似,只不過它有第二個可選參數用于指定字符編碼。例如得到UTF-8的字符串$str長度,可以用 mb_strlen($str,'UTF-8')。如果省略第二個參數,則會使用PHP的內部編碼。內部編碼可以通過 mb_internal_encoding()函數得到。需要注意的是,mb_strlen并不是PHP核心函數,使用前需要確保在php.ini中加載 了php_mbstring.dll,即確保“extension=php_mbstring.dll”這一行存在并且沒有被注釋掉,否則會出現未定義函 數的問題。
?
實例: 中文,用16進制轉換
$string = ",";$length = strlen($string); for($i=0;$i<$length;$i++){ $result[] = '0x' . strtolower(base_convert(ord($string{$i}), 10, 16));//ord($string[$i]); } echo 'chr(' . implode(') . chr(', $result) . ')';?
$tags = str_replace(array(chr(0xa3).chr(0xac), chr(0xa1).chr(0x41), chr(0xef).chr(0xbc).chr(0x8c)), ',', censor($tags));
?
?
轉載于:https://www.cnblogs.com/bandbandme/p/3154186.html
總結
以上是生活随笔為你收集整理的[转]PHP程序中的汉字编码探讨的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle 11gR2 RAC 中的
- 下一篇: JS第一个动画