编码方式和转码

来源:互联网 发布:mac创建新文件夹 编辑:程序博客网 时间:2024/06/05 09:36

以下内容是根据网上资料和个人理解整理出来的知识概要,如有错误,欢迎拍砖。

常用编码方式

常见的有四种:UTF-8、GB2312、GBK、GB18030。

先撇开UTF-8不谈,GB2312、GBK、GB18030这三种编码可以说都是为了汉字诞生的,三者的区别,可以简单理解为字符集大小的差异:GB2312 < GBK < GB18030。在这个不断扩充的过程中,少数民族语言、韩文、日文等各种字符也都被收录进来,发展到GB18030这一代,已经把世界大多民族的文字符号都囊括在内了。虽然GB18030的字符集可谓是最全面的,但是Windows系统下中文(中国)区域对应的默认代码页还是GBK。
那么,UTF-8又是怎么回事呢?要想理解她,必须先了解Unicode是什么东东。

大一统的Unicode

Unicode是为了世界和平和统一而诞生的。高大上吧,其实原理很简单:她把世界上所有的字符都列了出来,然后给每个字符分配了一个唯一编号,不管是什么平台也不管是什么语言,这个编号都不会发生改变。这种编码方式对应的通用字符集叫做UCS(Universal Character Set,UCS)-2。USC-2后面有个数字2是因为,目前的Unicode使用16位编码空间,即每个字符对应两个字节。
说到这里,终于可以揭开UTF-8的真面目了。她的全称是:Unicode Transformation Format-8bit。简单来说,UTF-8就是Unicode的一种实现方式或者说表现形式,主要是为了降低传输成本。她是一种可变长度字符编码方式,通常一个英文字符占用一个字节,一个汉字占用三个字节。对于绝大多数汉字而言,使用GB2312/GBK/GB18030是可以用两个字节表示的,因此对于汉字来说,使用UTF-8编码的弊端是会占用更多空间,但是由于UTF-8是基于Unicode的,她的优点在于:世界通用。

关于转码

铺垫了那么多,本文的重点终于出现了,那就是不同编码方式如何转换?其实很简单,那就是通过Unicode码做桥梁,实现GB2312/GBK/GB18030和UTF-8的相互转换。
可是如果这么简单,为何中文转码总会出现各种各样的问题呢?从这里开始水就深了,非要一句话总结的话,只能说汉字博大精深啊。下面列几个数字大家感受下。
在Unicode 5.0的99089个字符中,有71226个字符与汉字有关。它们的分布如下:

Block名称开始码位结束码位字符数CJK统一汉字4E009FBB20924 CJK统一汉字扩充A34004DB56582 CJK统一汉字扩充B200002A6D642711 CJK兼容汉字F900FA2D302 CJK兼容汉字FA30FA6A59 CJK兼容汉字FA70FAD9106CJK兼容汉字补充2F8002FA1D542如果不算兼容汉字,Unicode目前支持的汉字总数是20924+6582+42711=70217。
更多相关资料请戳:
字符集和字符编码(Charset & Encoding) 
Unicode、GB2312、GBK和GB18030中的汉字 

GB18030编码研究以及GBK、GB18030与Unicode的映射 

case分享

下面说一下我遇到的转码问题。
一句话说重点:UTF-8转GBK时,映射到Unicode码中PUA(Private Use Area,用户造字区)码位的GBK码,用php中的mb_convert_encoding函数不能正确转码。
这句话看起来比较绕,简单点说是这样子的:
UTF-8转GBK需要先将UTF-8转Unicode,这一步是没有问题的。然后从Unicode转GBK,绝大部分汉字也都是没问题的。但是,,,有那么一些汉字(查资料得知是80个),GBK的收录时间早于Unicode,所以这些汉字的GBK码对应的Unicode码最开始是用Unicode自定义区的码位来映射的。大概是因为mb_convert_encoding函数只能支持映射到Unicode非PUA码位的字符转码,所以在给这些汉字转码时出现了错误。(这是推论出来的,未经验证)
解决这个问题有两个办法:
1、升级php版本到5.4+,因为mb_convert_encoding函数从5.4起支持GB18030字符集,这80个字符中有66个在GB18030中映射到了Unicode的非PUA码位。注意,对于其余14个字符,此办法仍旧不能正确转码。
2、针对这80个特殊字符,建立一张从Unicode码到GBK码的映射表。以下为测试通过的代码:

<?php/** * 转码工具类 */class ds_TranscodingModel {        /**     * 特殊字符从unicode码到gbk码的映射     */    private $transDict = array(        'e815' => 'fe50',        'e816' => 'fe51',        'e817' => 'fe52',        'e818' => 'fe53',        'e819' => 'fe54',        'e81a' => 'fe55',        'e81b' => 'fe56',        'e81c' => 'fe57',        'e81d' => 'fe58',        'e81e' => 'fe59',        'e81f' => 'fe5a',        'e820' => 'fe5b',        'e821' => 'fe5c',        'e822' => 'fe5d',        'e823' => 'fe5e',        'e824' => 'fe5f',        'e825' => 'fe60',        'e826' => 'fe61',        'e827' => 'fe62',        'e828' => 'fe63',        'e829' => 'fe64',        'e82a' => 'fe65',        'e82b' => 'fe66',        'e82c' => 'fe67',        'e82d' => 'fe68',        'e82e' => 'fe69',        'e82f' => 'fe6a',        'e830' => 'fe6b',        'e831' => 'fe6c',        'e832' => 'fe6d',        'e833' => 'fe6e',        'e834' => 'fe6f',        'e835' => 'fe70',        'e836' => 'fe71',        'e837' => 'fe72',        'e838' => 'fe73',        'e839' => 'fe74',        'e83a' => 'fe75',        'e83b' => 'fe76',        'e83c' => 'fe77',        'e83d' => 'fe78',        'e83e' => 'fe79',        'e83f' => 'fe7a',        'e840' => 'fe7b',        'e841' => 'fe7c',        'e842' => 'fe7d',        'e843' => 'fe7e',        'e844' => 'fe80',        'e845' => 'fe81',        'e846' => 'fe82',        'e847' => 'fe83',        'e848' => 'fe84',        'e849' => 'fe85',        'e84a' => 'fe86',        'e84b' => 'fe87',        'e84c' => 'fe88',        'e84d' => 'fe89',        'e84e' => 'fe8a',        'e84f' => 'fe8b',        'e850' => 'fe8c',        'e851' => 'fe8d',        'e852' => 'fe8e',        'e853' => 'fe8f',        'e854' => 'fe90',        'e855' => 'fe91',        'e856' => 'fe92',        'e857' => 'fe93',        'e858' => 'fe94',        'e859' => 'fe95',        'e85a' => 'fe96',        'e85b' => 'fe97',        'e85c' => 'fe98',        'e85d' => 'fe99',        'e85e' => 'fe9a',        'e85f' => 'fe9b',        'e860' => 'fe9c',        'e861' => 'fe9d',        'e862' => 'fe9e',        'e863' => 'fe9f',        'e864' => 'fea0',    );        /**     * 汉字转Unicode编码     * @param string $str 原始汉字的字符串     * @param string $encoding 原始汉字的编码     * @param boot $ishex 是否为十六进制表示(支持十六进制和十进制)     * @param string $prefix 编码后的前缀     * @param string $postfix 编码后的后缀     */    function unicode_encode($str, $encoding = 'UTF-8', $ishex = false, $prefix = '&#', $postfix = ';') {        $str = mb_convert_encoding($str, 'UCS-2', $encoding);        $arrstr = str_split($str, 2);        $unistr = '';        for($i = 0, $len = count($arrstr); $i < $len; $i ++) {            $dec = $ishex ? bin2hex($arrstr[$i]) : hexdec(bin2hex($arrstr[$i]));            $unistr .= $prefix . $dec . $postfix;        }        return $unistr;    }        /**     * Unicode编码转汉字     * @param string $str Unicode编码的字符串     * @param string $decoding 原始汉字的编码     * @param boot $ishex 是否为十六进制表示(支持十六进制和十进制)     * @param string $prefix 编码后的前缀     * @param string $postfix 编码后的后缀     */    function unicode_decode($unistr, $encoding = 'UTF-8', $ishex = false, $prefix = '&#', $postfix = ';') {        $arruni = explode($prefix, $unistr);        $unistr = '';        for($i = 1, $len = count($arruni); $i < $len; $i ++) {            if (strlen($postfix) > 0) {                $arruni[$i] = substr($arruni[$i], 0, strlen($arruni[$i]) - strlen($postfix));            }            $temp = $ishex ? hexdec($arruni[$i]) : intval($arruni[$i]);            $unicode = ($temp < 256) ? chr(0) . chr($temp) : chr($temp / 256) . chr($temp % 256);            $tempHex = bin2hex($unicode);            if(array_key_exists($tempHex, $this->transDict)) {                $unistr .= pack("H*",$this->transDict[$tempHex]);            } else {                $unistr .= mb_convert_encoding($unicode, $encoding, 'UCS-2');            }        }        return $unistr;    }        /**     * utf8编码转gbk编码     * @param string $str                 * @return string     */    function utf8_to_gbk($str) {        $gbkStr = mb_convert_encoding($str, 'GBK', 'UTF-8');        $utf8_str = mb_convert_encoding($gbkStr, 'UTF-8', 'GBK');        if($utf8_str == $str) {            return $gbkStr;        }        $unistr = self::unicode_encode($str, 'UTF-8');        $str = self::unicode_decode($unistr, 'GBK');        return $str;    }?>


0 0
原创粉丝点击