GD输出汉字的函数的分析


Posted in PHP onOctober 09, 2006

    很早以前找到一个把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字符这一步骤,放在判断了字符属于西文还是属于汉字的条件分支里,据此决定截取一个字节还是三个字节。于是结果正确了!

PHP 相关文章推荐
在Windows下编译适用于PHP 5.2.12及5.2.13的eAccelerator.dll(附下载)
May 04 PHP
php站内搜索并高亮显示关键字的实现代码
Dec 29 PHP
单一index.php实现PHP任意层级文件夹遍历(Zjmainstay原创)
Jul 31 PHP
基于PHP对XML的操作详解
Jun 07 PHP
分享一则PHP定义函数代码
Feb 26 PHP
PHP自毁程序(慎用)
Jul 09 PHP
详解js异步文件加载器
Jan 24 PHP
laravel学习教程之关联模型
Jul 30 PHP
PHP面向对象继承用法详解(优化与减少代码重复)
Dec 02 PHP
CodeIgniter框架数据库基本操作示例
May 24 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
Jun 13 PHP
PHP PDOStatement::nextRowset讲解
Feb 01 PHP
类的另类用法--数据的封装
Oct 09 #PHP
最小化数据传输――在客户端存储数据
Oct 09 #PHP
网站加速 PHP 缓冲的免费实现方法
Oct 09 #PHP
Windows下PHP的任意文件执行漏洞
Oct 09 #PHP
通过对服务器端特性的配置加强php的安全
Oct 09 #PHP
用Zend Encode编写开发PHP程序
Oct 09 #PHP
在php中使用sockets:从新闻组中获取文章
Oct 09 #PHP
You might like
Apache, PHP在Windows 9x/NT下的安装与配置 (二)
2006/10/09 PHP
php运行出现Call to undefined function curl_init()的解决方法
2010/11/02 PHP
PHP数组排序之sort、asort与ksort用法实例
2014/09/08 PHP
symfony表单与页面实现技巧
2015/01/26 PHP
CL vs ForZe BO5 第三场 2.13
2021/03/10 DOTA
javascript 类定义的4种方法
2009/09/12 Javascript
javascript showModalDialog模态对话框使用说明
2009/12/31 Javascript
xss文件页面内容读取(解决)
2010/11/28 Javascript
JS弹出对话框返回值代码(asp.net后台)
2010/12/28 Javascript
JS中判断JSON数据是否存在某字段的方法
2014/03/07 Javascript
Jquery倒计时源码分享
2014/05/16 Javascript
jquery设置表单元素为不可用的简单代码
2016/07/04 Javascript
jQuery中show与hide方法用法示例
2016/09/16 Javascript
jQuery的三种bind/One/Live/On事件绑定使用方法
2017/02/23 Javascript
详解React Native网络请求fetch简单封装
2017/08/10 Javascript
解析vue中的$mount
2017/12/21 Javascript
详解nodeJs文件系统(fs)与流(stream)
2018/01/24 NodeJs
express如何使用session与cookie的方法
2018/01/30 Javascript
JavaScript解决浮点数计算不准确问题的方法分析
2018/07/09 Javascript
javascript数据类型中的一些小知识点(推荐)
2019/04/18 Javascript
jQuery实现弹出层效果
2019/12/10 jQuery
vue中如何添加百度统计代码
2020/12/19 Vue.js
[01:14]3.19DOTA2发布会 三代刀塔人第二代
2014/03/25 DOTA
Python变量和数据类型详解
2017/02/15 Python
视觉直观感受若干常用排序算法
2017/04/13 Python
Python进阶-函数默认参数(详解)
2017/05/18 Python
基于python指定包的安装路径方法
2018/10/27 Python
Python 异常处理Ⅳ过程图解
2019/10/18 Python
html5的canvas方法使用指南
2014/12/15 HTML / CSS
ORACLE第二个十问
2013/12/14 面试题
缓刑人员的思想汇报
2014/01/11 职场文书
应届生简历中的自我评价
2014/01/13 职场文书
《真想变成大大的荷叶》教学反思
2014/04/14 职场文书
2014年感恩节活动策划方案
2014/10/06 职场文书
签订劳动合同通知书
2015/04/16 职场文书
Win11 S Mode版本泄露 正式上线后叫做Windows 11 SE
2021/11/21 数码科技