php下GB跟UTF-8编码的互相转换

    在php程序开发中,有时候要遇到GB2312(GBK)码跟UTF-8之间转换的问题, 
尤其是用php进行WAP开发的时候。因为手机能够显示的是UTF-8编码,通过WAP 
提交的文字也是用UTF-8编码。为了能够正常显示和处理用户输入的中文,经常 
会遇到GB2312(GBK)跟UTF-8之间的转码问题。 
    目前在网上能够找到GB2312->UTF-8的php示例程序,而UTF-8->GB2312(GBK) 
的转码程序我没有找到。另外,Jsp/Java下有现成的转码函数,其实linux平台 
下的php也有现成的函数,只是默认php编译的时候没有加载该模块。 
    基于以上考虑,本人在原有GB2312->UTF-8转码程序的基础上,写了一个 
UTF-8到GB的转码程序。另外,在第二部分讲了一下如何配置和使用php自带的 
函数来进行转码。 
 
【第一部分】使用GB跟Unicode码表进行转换 
    汉字的GB2312/GBK(以下简称GB)跟Unicode的汉字编码之间有一个一一对应 
的关系,有一张码表列出了他们的对应关系。不过这个码表中GB码跟实际的php 
中用bin2hex函数获得GB码值(ASCII)之间差了0x8080,需要做一下处理。 
 
1、GB->UTF-8 
    中国php联盟上有这样一篇文章写了如何转换,该文章为 
     http://www.phpx.com/show.php?d=col&i=58    
    这篇文章就是基于上面的码表来转换的,该码表也在哪有得下载 
     http://www.phpx.com/download/utf8/gb2312.txt 
     
    但是这篇文章只给出了GB->UTF-8和Unicode->UTF8的转码函数,缺少一个 
UTF-8到GB的转码函数。参考他的文章,本人写了一个这样的函数。 
    另外,我将他写的函数用类进行封装了一下,写了一个convert类。因为原 
文每次调用转码函数都要读取一次gb2312.txt文件,而I/O操作非常好时间,如 
果一个php文件中多次调用这个函数的话,严重影响响应速度。因此用一个类来 
封装,在类的构造函数里读取gb2312.txt,这样一个php实例化一个convert, 
只需进行一次I/O操作。我做个一个测试,封装好的转码函数,运行10000次需 
要3秒,而原来的函数运行100次用了16秒。         
    该类的部分代码如下: 
class  convert { 
     
    
// gb2312和utf-8对应的编码文件 
     var   $filename   =   " /usr/local/system/phplib/gb2312.txt " ;            
     
    
var   $codetable   =   array ();              // 码表读取后存入这个数组 
     
    //构造函数 

     function  convert() { 
        
$tmp   =   file ( $this -> filename); 
        
while list ( $key , $value =   each ( $tmp ) ) 
 
            
$this -> codetable[ hexdec ( substr ( $value , 0 , 6 ))]  =   
                 
substr ( $value , 7 , 6 ); 
    } 
     
    
// GB->UTF-8 
     function  toUTF8( $gb ) { 
        
// 转换过程可参考上面列出的文章,这里就不贴了 
         return   $utf8 ;         
    } 
     
}     
 
2.UTF-8->GB 
    上面给出的那个gb2312是gb跟Unicode之间的对应关系,而UTF-8跟Unicode之 
间也有一个转换,要从UTF-8->GB,就必须先从UTF-8->Unicode,再用上面的表来 
Unicode->GB. 
    UTF-8是Unicode的Transformation Format,因为Unicode编码中存在着 
0x0034酱紫的字符,这个字符的高位字节是0x00,跟C语言下string的结束标 
志/0冲突,会引起判断字符串结束的混乱,因此有了个Transformation  
Format ---UTF-8。 
 
    从Unicode 到UTF-8的标准可参见RFC-2279,其实主要的一点我们需要知道 
下面这张对应的转换关系: 
   UCS-4 range (hex.)           UTF-8 octet sequence (binary) 
   0000 0000-0000 007F   0xxxxxxx 
   0000 0080-0000 07FF   110xxxxx 10xxxxxx 
   0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
 
   0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
   0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
   0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx 
 
这张表左边一列是Unicode编码,右边一列是UTF-8编码。汉字的编码范围在第三 
行。这个表的意思(以第三行汉字为例):汉字编码是双字节,比如“爱”的 
Unicode编码为0x7231(在上面的gb2312中对应有),她的二进制编码是 
0111 0010 0011 0001 
根据上面的第三行,取“爱”的二进制后六位(0~5),前面加10(为1011 0001), 
再往前第6~11位前再加10(为1000 1000),最高的四位前加1110(为1110 0111), 
于是“爱”的UTF-8编码为: 
1110 0111 1000 1000 1011 0001 ( 0xe788b1) 
 
那么反过来UTF-8到Unicode的话,只要把UTF-8的二进制的第0~5,8~13,16~19位取 
出来组合成双字节的Unicode码就可以了。采用php的位操作(或,与,移位)就 
可实现 
 
$unicode = (($utf & 0x0F0000)>>4) | (($utf & 0x3F00)>>2) | ($utf &  
    0x3F); 
 
获得了Unicode值后,再从上面的gb2312.txt里找到对应的gb2312码,在该码上加 
上0x8080(因为上文说过,这个码表跟实际汉字bin2hex出来的值差0x8080,也就是 
汉字的最高位是为1)。 
 
于是,在上面的convert类中可以加上一个UTF2GB的函数。代码如下: 
    
function  UTF2gb( $str ) { 
        
if ! trim ( $str ) ) 
            
return   $str
        
$reverse   =   array (); 
        
while list ( $key , $value =   each ( $this -> codetable) ) 
            
$reverse [ hexdec ( $value )]  =   $key
        
$gb   =   ""
        
while ( $str ) { 
            
if  (  ord ( substr ( $str , 0 , 1 )) > 0xE0   ) 
            { 
                
$tmp   =   substr ( $str , 0 , 3 ); 
                
$str   =   substr ( $str , 3 , strlen ( $str )); 
                
$utf   =   hexdec ( bin2hex ( $tmp )); 
                
$unicode   =  (( $utf   &   0x0F0000 ) >> 4 |  (( $utf   &   0x3F00 ) >> 2
                     
|  ( $utf   &   0x3F ) ; 
                
$gb   =   $gb   .    pack ( " n " , ( $reverse [ $unicode ]) | 0x8080  ); 
            } 
            
else  
            { 
                
$gb   =   $gb   .   substr ( $str , 0 , 1 ); 
                
$str   =   substr ( $str , 1 , strlen ( $str )); 
 
                 
            } 
        } 
        
return   $gb ;         
    } 
    注:1、这里定义了一个新的Hashtable(其实是数组),把原来的codetable的 
key和value对调了一下,为了方便索引。而我没有把这个数组在Constructor中初始 
化,因为UTF-8->GB的函数我调用的比较少,为了程序优化考虑,放在了这里。 
        2、pack("n",bin_var)函数是把二进制编码转换为字符的一个函数,可参 
考php manual.  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值