沉于思考,默默学习!

你不能预知明天,但你可以利用今天。你不能样样顺利,但你可以事事尽力!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  • 起因:

最近遇到一件事情,一个接口能够接收传入编码可能是utf-8,gbk 两种。 做过编码方面转换的同学应该知道的,是什么编码不会在字符串里面有什么标记位的。不过utf-8编码有特殊性,因此可以通过正则表达式来检查。只要发现是utf-8编码。就转换,不是utf-8就当gbk处理。 编码一些常见问题可以查看:由web程序出现乱码开始挖掘(Bom头、字符集与乱码)

  • 行动:

知道这个原理,马上领任务,开始工作。 想到php版本有个mbstring模块可以进行编码检测转换:

<?php
//当前编码是gbk
$str="中国";
$aStrList=array($str,iconv('gbk','utf-8',$str));

foreach ($aStrList as $v)
{
	echo mb_convert_encoding($v,'gbk','utf-8,gbk'),"\r\n";
}
 
运行结果:
image 
 
两个不同编码的“中国”,用一个函数mb_convert_encoding就可以自动转换成gbk编码。首页,尝试用utf-8解码,如果出现问题,就会用gbk转码。看来问题解决了,哈哈,可以交差了……
 
  1. 问题:
发布后,平静了几天,突然接到反馈:有中文:”袁小”解码出错。⊙﹏⊙b汗 …… ,想……(难道php内置检测模块有问题,或是我哪里欠缺……)
image 
⊙﹏⊙b汗……  看来果然有问题,查询手册:mbstring 模块编码检查,只是识别字符串部分编码,发现与某个字符集匹配上,就认为它属于那种编码。 这不属于它的bug,因为字符串本身没有编码信息标识,没有那个语言能够完全检测通过。 
 
  1. 问题:
能不能自己写一个检查正则表达式看下到底怎么样呢?要写正则表达式,首先须了解utf8编码规范,查看:http://zh.wikipedia.org/zh/UTF-8 

image

目前编码集合只有这样6个维度:php得到维度代码

<?php
//得到utf8字编码各个维度的范围 
echo base_convert('1111111',2,16),"\r\n";//维度1
echo base_convert('10000000',2,16),base_convert('10111111',2,16),"\r\n";

echo base_convert('11000000',2,16),base_convert('11011111',2,16),"\r\n";//维度2
echo base_convert('11100000',2,16),base_convert('11101111',2,16),"\r\n";//维度3
echo base_convert('11110000',2,16),base_convert('11110111',2,16),"\r\n";//维度4
echo base_convert('11111000',2,16),base_convert('11111011',2,16),"\r\n";//维度5
echo base_convert('11111100',2,16),base_convert('11111101',2,16),"\r\n";//维度6

运行结果:

image

  1. 通过上面6个维度得到得到对应的正则表达式:

[\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5}

以上分别是各个维度范围

<?php
//当前编码是gbk
$str="";
echo urlencode($str);
echo is_utf8($str);
function is_utf8($str)
{
	///utf8编码正则检测函数
	///copyright qq:8292669  http://www.cnblogs.com/chengmo
	$re='/^([\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})+$/';
	return preg_match($re,$str);
}
上面执行结果返回为1,然后”袁“本身应该是gbk编码。看来上面函数还是不能彻底检查utf8编码。分析原因,从上面正则可以看到,utf8的6个维度对应字节长度从1-6字节。 而gbk是1-2个字节。因此他们之间会在1-2个字节长度地方检查出现重合。1个字节的时候gbk与utf8的 编码与字符对应关系都一样,但是2个字节时候,对应编码与字符各不相同。
 
通过查询gbk编码表:http://www.knowsky.com/resource/gb2312tbl.htm 进一步确认,范围会在:
[c0-df][a0-bf]  之内汉字都会有问题了。 如果纯这个范围的汉字组合为字符串就会出现判断不了情况。如果它与其它范围字符组合都可以正确的判断出来。
 

GBK与UTF8字符集重叠对应的字符是:(gbk编码表)

 
code  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
C0A0     馈 愧 溃 坤 昆 捆 困 括 扩 廓 阔 垃 拉 喇 蜡
C0B0  腊 辣 啦 莱 来 赖 蓝 婪 栏 拦 篮 阑 兰 澜 谰 揽
C1A0     痢 立 粒 沥 隶 力 璃 哩 俩 联 莲 连 镰 廉 怜
C1B0  涟 帘 敛 脸 链 恋 炼 练 粮 凉 梁 粱 良 两 辆 量
C2A0     隆 垄 拢 陇 楼 娄 搂 篓 漏 陋 芦 卢 颅 庐 炉
C2B0  掳 卤 虏 鲁 麓 碌 露 路 赂 鹿 潞 禄 录 陆 戮 驴
C3A0     谩 芒 茫 盲 氓 忙 莽 猫 茅 锚 毛 矛 铆 卯 茂
C3B0  冒 帽 貌 贸 么 玫 枚 梅 酶 霉 煤 没 眉 媒 镁 每
C4A0     摹 蘑 模 膜 磨 摩 魔 抹 末 莫 墨 默 沫 漠 寞
C4B0  陌 谋 牟 某 拇 牡 亩 姆 母 墓 暮 幕 募 慕 木 目
C5A0     拧 泞 牛 扭 钮 纽 脓 浓 农 弄 奴 努 怒 女 暖
C5B0  虐 疟 挪 懦 糯 诺 哦 欧 鸥 殴 藕 呕 偶 沤 啪 趴
C6A0     啤 脾 疲 皮 匹 痞 僻 屁 譬 篇 偏 片 骗 飘 漂
C6B0  瓢 票 撇 瞥 拼 频 贫 品 聘 乒 坪 苹 萍 平 凭 瓶
C7A0     恰 洽 牵 扦 钎 铅 千 迁 签 仟 谦 乾 黔 钱 钳
C7B0  前 潜 遣 浅 谴 堑 嵌 欠 歉 枪 呛 腔 羌 墙 蔷 强
C8A0     取 娶 龋 趣 去 圈 颧 权 醛 泉 全 痊 拳 犬 券
C8B0  劝 缺 炔 瘸 却 鹊 榷 确 雀 裙 群 然 燃 冉 染 瓤
C9A0     伞 散 桑 嗓 丧 搔 骚 扫 嫂 瑟 色 涩 森 僧 莎
C9B0  砂 杀 刹 沙 纱 傻 啥 煞 筛 晒 珊 苫 杉 山 删 煽
CAA0     省 盛 剩 胜 圣 师 失 狮 施 湿 诗 尸 虱 十 石
CAB0  拾 时 什 食 蚀 实 识 史 矢 使 屎 驶 始 式 示 士
CBA0     恕 刷 耍 摔 衰 甩 帅 栓 拴 霜 双 爽 谁 水 睡
CBB0  税 吮 瞬 顺 舜 说 硕 朔 烁 斯 撕 嘶 思 私 司 丝
CCA0     獭 挞 蹋 踏 胎 苔 抬 台 泰 酞 太 态 汰 坍 摊
CCB0  贪 瘫 滩 坛 檀 痰 潭 谭 谈 坦 毯 袒 碳 探 叹 炭
CDA0     汀 廷 停 亭 庭 挺 艇 通 桐 酮 瞳 同 铜 彤 童
CDB0  桶 捅 筒 统 痛 偷 投 头 透 凸 秃 突 图 徒 途 涂
CEA0     巍 微 危 韦 违 桅 围 唯 惟 为 潍 维 苇 萎 委
CEB0  伟 伪 尾 纬 未 蔚 味 畏 胃 喂 魏 位 渭 谓 尉 慰
CFA0     稀 息 希 悉 膝 夕 惜 熄 烯 溪 汐 犀 檄 袭 席
CFB0  习 媳 喜 铣 洗 系 隙 戏 细 瞎 虾 匣 霞 辖 暇 峡
D0A0     小 孝 校 肖 啸 笑 效 楔 些 歇 蝎 鞋 协 挟 携
D0B0  邪 斜 胁 谐 写 械 卸 蟹 懈 泄 泻 谢 屑 薪 芯 锌
D1A0     选 癣 眩 绚 靴 薛 学 穴 雪 血 勋 熏 循 旬 询
D1B0  寻 驯 巡 殉 汛 训 讯 逊 迅 压 押 鸦 鸭 呀 丫 芽
D2A0     摇 尧 遥 窑 谣 姚 咬 舀 药 要 耀 椰 噎 耶 爷
D2B0  野 冶 也 页 掖 业 叶 曳 腋 夜 液 一 壹 医 揖 铱
D3A0     印 英 樱 婴 鹰 应 缨 莹 萤 营 荧 蝇 迎 赢 盈
D3B0  影 颖 硬 映 哟 拥 佣 臃 痈 庸 雍 踊 蛹 咏 泳 涌
D4A0     浴 寓 裕 预 豫 驭 鸳 渊 冤 元 垣 袁 原 援 辕
D4B0  园 员 圆 猿 源 缘 远 苑 愿 怨 院 曰 约 越 跃 钥
D5A0     铡 闸 眨 栅 榨 咋 乍 炸 诈 摘 斋 宅 窄 债 寨
D5B0  瞻 毡 詹 粘 沾 盏 斩 辗 崭 展 蘸 栈 占 战 站 湛
D6A0     帧 症 郑 证 芝 枝 支 吱 蜘 知 肢 脂 汁 之 织
D6B0  职 直 植 殖 执 值 侄 址 指 止 趾 只 旨 纸 志 挚
D7A0     住 注 祝 驻 抓 爪 拽 专 砖 转 撰 赚 篆 桩 庄
D7B0  装 妆 撞 壮 状 椎 锥 追 赘 坠 缀 谆 准 捉 拙 卓
D8A0     亍 丌 兀 丐 廿 卅 丕 亘 丞 鬲 孬 噩 丨 禺 丿
D8B0  匕 乇 夭 爻 卮 氐 囟 胤 馗 毓 睾 鼗 丶 亟 鼐 乜
D9A0     佟 佗 伲 伽 佶 佴 侑 侉 侃 侏 佾 佻 侪 佼 侬
D9B0  侔 俦 俨 俪 俅 俚 俣 俜 俑 俟 俸 倩 偌 俳 倬 倏
DAA0     凇 冖 冢 冥 讠 讦 讧 讪 讴 讵 讷 诂 诃 诋 诏
DAB0  诎 诒 诓 诔 诖 诘 诙 诜 诟 诠 诤 诨 诩 诮 诰 诳
DBA0     邸 邰 郏 郅 邾 郐 郄 郇 郓 郦 郢 郜 郗 郛 郫
DBB0  郯 郾 鄄 鄢 鄞 鄣 鄱 鄯 鄹 酃 酆 刍 奂 劢 劬 劭
DCA0     堋 堍 埽 埭 堀 堞 堙 塄 堠 塥 塬 墁 墉 墚 墀
DCB0  馨 鼙 懿 艹 艽 艿 芏 芊 芨 芄 芎 芑 芗 芙 芫 芸
DDA0     荨 茛 荩 荬 荪 荭 荮 莰 荸 莳 莴 莠 莪 莓 莜
DDB0  莅 荼 莶 莩 荽 莸 荻 莘 莞 莨 莺 莼 菁 萁 菥 菘
DEA0     蕖 蔻 蓿 蓼 蕙 蕈 蕨 蕤 蕞 蕺 瞢 蕃 蕲 蕻 薤
DEB0  薨 薇 薏 蕹 薮 薜 薅 薹 薷 薰 藓 藁 藜 藿 蘧 蘅
DFA0     摺 撷 撸 撙 撺 擀 擐 擗 擤 擢 攉 攥 攮 弋 忒
DFB0  甙 弑 卟 叱 叽 叩 叨 叻 吒 吖 吆 呋 呒 呓 呔 呖
只要在这些范围的任意汉字组合一起,都会别解码为utf8,这个也就是utf8编码不能完全识别根本原因。因此需要彻底检查utf8编码,需要排除这些干扰.
  1. 整理后的PHP
  2. <?php
    //当前编码是gbk  本函数以gbk与utf8为例子
    $str="袁小";
    echo checkUtf8($str);
    echo checkUtf8(iconv('gbk','utf-8',$str));
    
    $str="辍 辎";
    echo checkUtf8($str);
    echo checkUtf8(iconv('gbk','utf-8',$str));
    
    
    /**
     *检测字符串是否是utf8编码*
     * @param string $str 输入字符串
     * @param string $extzh 排除重合中文,
     * @return 1|0 1是utf8 0不为utf8
     */
    function checkUtf8($str,$extzh=1)
    {
    	///utf8编码正则检测函数
    	///copyright qq:8292669  
    	///author  程默  http://www.cnblogs.com/chengmo
    
    	//gbk,utf8重叠的范围是:[c0-df][a0-bf] 这块字符在utf8中有,在gbk编码没有对应字符因此向gbk转换会出现"?"号
    	if($extzh==1)
    	{
    		$re='/^([\x01-\x7f]|[\xc0-\xdf][\xa0-\xbf])+$/';  ///这部分字符如果当作utf8处理,在转换为gbk时候就会出现问题"?"号。因此直接返回不为utf8
    		if(preg_match($re,$str))  ///公共字符验证成功
    		{
    			return 0;  ///不是utf8
    		}
    	}
    	$re='/^([\x01-\x7f]|[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5})+$/';
    	return preg_match($re,$str);
    }

image

以上是一个折中的方法,在国内一般web程序是:gbk,utf8两种,用上面这个方法基本可以解决问题,可以避免误将gbk识别为utf8,然后将它从utf8->gbk转码,出现”?”号朋友,你有什么更好的方法欢迎交流!!

作者:chengmo QQ:8292669
出处:http://www.cnblogs.com/chengmo
本文版权归作者和博客园共有,欢迎转载,请务必添加原文链接。

 
 
 
posted on 2011-02-19 21:59  程默  阅读(7939)  评论(14编辑  收藏  举报