GD輸出漢字的函數的分析(函數代碼系轉帖)

來源:互聯網
上載者:User
函數|漢字     很早以前找到一個把GB碼轉化為UTF-8的函數,配合一個GB到UNICODE的對照表(gb2312.txt),用於在GD中輸出漢字。後來發現在欲輸出的內容中含有西文字元時,會出現混亂。後來找到了修改後的代碼,解決了問題。現將兩個函數做一對比分析如下。

首先,這是一個UNICODE到UTF-8編碼轉換的函數,這一部分修改前後沒有變化:
function u2utf8($c)
{
for($i=0;$i<count($c);$i++)
$str="";
if ($c < 0x80) {
$str.=$c;
}
else if ($c < 0x800) {
$str.=(0xC0 | $c>>6);
$str.=(0x80 | $c & 0x3F);
}
else if ($c < 0x10000) {
$str.=(0xE0 | $c>>12);
$str.=(0x80 | $c>>6 & 0x3F);
$str.=(0x80 | $c & 0x3F);
}
else if ($c < 0x200000) {
$str.=(0xF0 | $c>>18);
$str.=(0x80 | $c>>12 & 0x3F);
$str.=(0x80 | $c>>6 & 0x3F);
$str.=(0x80 | $c & 0x3F);
}
return $str;
}

這裡完全是按照UTF-8編碼的規則,通過判斷字元屬於不同的UNICODE編碼段範圍,進行不同的移位和位與操作,以轉化為UTF-8編碼。關於該規則可參考http://www.utf8.org/上的說明。

這是修改前的GB轉化為UTF-8編碼的函數,其中調用了上面的u2utf8函數。
function gb2utf8($gb)     /* Program writen by sadly www.phpx.com  */
{
if(!trim($gb))
return $gb;
$filename="gb2312.txt";
$tmp=file($filename);
$codetable=array();
while(list($key,$value)=each($tmp))
$codetable[hexdec(substr($value,0,6))]=substr($value,7,6);
$utf8="";
while($gb)
{
if (ord(substr($gb,0,1))>127)
{
$this=substr($gb,0,2);
$gb=substr($gb,2,strlen($gb));
$utf8.=u2utf8(hexdec($codetable[hexdec(bin2hex($this))-0x8080]));
}
else
{
$gb=substr($gb,1,strlen($gb));
$utf8.=u2utf8(substr($gb,0,1));
}
}

$ret="";
for($i=0;$i<strlen($utf8);$i+=3)
$ret.=chr(substr($utf8,$i,3));

return $ret;
}
函數中while迴圈部分,把漢字逐個按照“對照表”轉化為UNICODE,再通過u2utf8函數轉化為UTF-8。但從中可以看出,while迴圈結束後,又用一個for迴圈,把每三個位元組合成了一個UTF-8字元(見http://www.utf8.org/上的規則說明,每個漢字的UTF-8編碼為三位元組),沒有考慮到其中的西文字元(西文字元的UTF-8編碼為一位元組)。所以,如果欲輸出的內容中不論是開始時出現西文字元,或是漢字當中穿插西文字元,轉化為UTF-8後,都會被按照“每三個位元組截取”的方式截開,導致亂碼。


以下是修改後的函數:
function gb2utf8($gb)    /* Program writen by sadly   modified by agun */
{
if(!trim($gb))
return $gb;
$filename="gb2312.txt";
$tmp=file($filename);
$codetable=array();
while(list($key,$value)=each($tmp))
$codetable[hexdec(substr($value,0,6))]=substr($value,7,6);

$ret="";
$utf8="";
while($gb)
{
if (ord(substr($gb,0,1))>127)
{
$this=substr($gb,0,2);
$gb=substr($gb,2,strlen($gb));
$utf8=u2utf8(hexdec($codetable[hexdec(bin2hex($this))-0x8080]));
for($i=0;$i<strlen($utf8);$i+=3)
$ret.=chr(substr($utf8,$i,3));
}
else
{
$ret.=substr($gb,0,1);
$gb=substr($gb,1,strlen($gb));
}
}
return $ret;
}

修改後的函數將 GB轉化為UNICODE、UNICODE轉化為UTF-8、幾個位元組合成一個UTF-8字元,這三個步驟在一個迴圈裡完成,尤其是幾個位元組合成一個UTF-8字元這一步驟,放在判斷了字元屬於西文還是屬於漢字的條件分支裡,據此決定截取一個位元組還是三個位元組。於是結果正確了!

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。