`
zhanchaojiang
  • 浏览: 112915 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

由编码识别遇到问题,思考utf8编码正则表达式(php版本)

 
阅读更多

 

  • 起因:

最近遇到一件事情,一个接口能够接收传入编码可能是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编码表)

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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
本文版权归作者和博客园共有,欢迎转载,请务必添加原文链接。

1
  
1
  
 
posted on 2011-02-19 21:59 程默 阅读(1846) 评论(13) 编辑 收藏

 

评论

#1楼 2011-02-19 22:29 易海之畔      
这是一段来自thinkphp编码转换的代码,经测试好像解码正常。不制作者能否再次测试一下,有可能本人测试有误。看了作者的文章,受教。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function auto_charset($fContents,$from='gbk',$to='utf-8'){
    $from   strtoupper($from)=='UTF8'? 'utf-8':$from;
    $to       strtoupper($to)=='UTF8'? 'utf-8':$to;
    if( strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents)) ){
        //如果编码相同或者非字符串标量则不转换
        return $fContents;
    }
    if(is_string($fContents) ) {
        if(function_exists('mb_convert_encoding')){
            return mb_convert_encoding ($fContents, $to, $from);
        }elseif(function_exists('iconv')){
            return iconv($from,$to,$fContents);
        }else{
            return $fContents;
        }
    }
    elseif(is_array($fContents)){
        foreach ( $fContents as $key => $val ) {
            $_key =     auto_charset($key,$from,$to);
            $fContents[$_key] = auto_charset($val,$from,$to);
            if($key != $_key )
                unset($fContents[$key]);
        }
        return $fContents;
    }
    else{
        return $fContents;
    }

}



分享到:
评论

相关推荐

    判断不同编码的正则表达式

    对于不同的字符编码(如GB2312、UTF-8等),其对应的正则表达式也会有所不同。本文将探讨如何通过PHP语言中的正则表达式来判断字符串是否为GB2312或UTF-8编码。 #### GB2312编码判断 GB2312是中国大陆使用的一种...

    正则表达式统计汉字

    这里的 `"utf-8"` 参数指定了字符串的编码方式,确保函数能够正确识别和计数。 ##### 5. 统计特定字符出现次数的方法 本例中,我们通过先用正则表达式移除所有非汉字字符,然后再统计剩余字符串的长度,以此来得到...

    正则表达式概述

    对于UTF-8编码,可以使用以下正则表达式: ```php /[\x{4e00}-\x{9fa5}]/u ``` 这里`u`修饰符表示Unicode模式,`[\x{4e00}-\x{9fa5}]`表示匹配所有中文字符。 #### 八、环视(断言) 环视(或称为零宽度断言)是...

    解析php利用正则表达式解决采集内容排版的问题

    文章标题指出了本文的核心内容是“利用正则表达式解决PHP采集内容排版问题”。在实际网络爬虫开发过程中,获取网页内容后,往往需要对内容进行整理和格式化,以适应后续的数据处理需求。正则表达式作为一种强大的...

    Patchwork UTF-8:处理UTF-8格式字符串的便携类库

    6. **正则表达式支持**:增强PHP的正则表达式引擎,使其能更好地处理UTF-8字符串,避免因编码不匹配导致的匹配失败。 7. **排序与比较**:按照Unicode规范对UTF-8字符串进行排序和比较,确保多语言数据的正确排序。...

    更新的自动识别网站编码并修改的php脚本

    php脚本自动批量更改网页编码,识别页面编码并转为utf-8。

    php 过滤emoji表情

    `u`修饰符告诉PHP使用UTF-8编码进行匹配。当然,这只是一个基本的例子,实际的正则表达式可能需要覆盖更多的emoji范围,以确保更全面的过滤。 文件名“php判断表情.txt”可能包含了更详细的代码示例或说明,可能是...

    php自动识别文字编码并转换为目标编码的方法

    为了解决这个问题,出现了可以部分识别UTF-8和GBK编码的safeEncoding函数。不过,它在复杂环境下可能不够准确。因此,进一步的方法是结合GBK和UTF-8编码的特点,利用正则表达式来判断UTF-8编码,并使用mb_convert_...

    基于PHP的自动链PHP utf-8开源版.zip

    【标题】"基于PHP的自动链PHP utf-8开源版.zip" 提供的是一个使用PHP编程语言开发的自动链接系统,该系统支持UTF-8编码。在网站开发中,自动链(AutoLink)通常用于将文本中的关键词或网址自动转化为超链接,提升...

    PHP截断标题且兼容utf8和gb2312编码

    总结来说,通过了解不同编码方式的特点,并运用正则表达式匹配和捕获组的概念,我们可以在PHP中实现一个既能够处理UTF-8编码,也能处理GB2312编码的标题截断功能。这种方法不仅保证了字符的正确截取,也使得网页标题...

    PHP实例开发源码—PhpColor php多彩贴吧GBK.zip

    6. **正则表达式处理**:在使用正则表达式匹配GBK编码的字符串时,需要考虑编码问题,否则可能会导致匹配失败。可以使用`preg_quote`函数转义字符串,并在正则表达式中使用`u`修饰符来处理多字节字符,如GBK。 7. *...

    关于php正则匹配汉字的方法介绍

    其正则表达式通常需要包含相应的编码范围,例如“/^[\x{4e00}-\x{9fa5}A-Za-z0-9_]+$/u”,但是需要注意的是,GBK和GB2312的编码范围和UTF-8不同,所以在不同编码环境下,需要对正则表达式进行相应的调整。...

    PHP 截取字符串 分别适合GB2312和UTF8编码情况

    示例中给出了`utf8Substr`函数,这个函数使用正则表达式来匹配和截取指定长度的UTF-8编码字符串。使用正则表达式的方法可以有效地处理不同长度的字符截取,但需要注意正则表达式的性能影响,特别是在处理大型字符串...

    用PHP将Unicode 转化为UTF-8的实现方法(推荐)

    上述文章中提供的PHP函数`unescape`展示了如何通过正则表达式匹配特定格式的字符串,然后利用`iconv`函数进行编码转换。`iconv`函数是一个强大的字符编码转换函数,能够将一种编码的字符串转换为另一种编码。 根据...

    php验证手机号码(支持归属地查询及编码为UTF8)

    此外,查询手机号码的归属地信息和处理字符串编码转换也是开发中经常遇到的问题。本篇文档将详细介绍如何使用PHP实现手机号码的验证、归属地查询以及字符串编码转换为UTF-8。 首先,我们来讨论手机号码验证的问题。...

    UTF8编码内的繁简转换的PHP类

    在非UTF-8编码的字符集中,如GB2312、GBK与BIG5等,繁体字和简体字通常由不同的字节序列表示,这为程序提供了较为直接的转换途径。然而,当使用UTF-8编码时,很多繁简对应的字节序列是相同的,这就需要程序能够识别...

    PHP实现自动识别原编码并对字符串进行编码转换的方法

    通过该方法,我们可以确保在处理文本数据时,不论原始文本是以何种字符编码形式存储的,都能够将其转换成目标编码格式,如常见的UTF-8编码,从而解决乱码问题,提高数据的兼容性和准确性。 在详细讲解知识点之前,...

    匹配中文的正则(GB2312/utf-8)

    当设置`u`修正符时,正则表达式会识别模式字符串为UTF-8编码,这样就能正确地匹配中文字符。例如,要匹配任意的中文字符,可以使用`\p{Han}`,它代表Unicode中的汉字符类别。 接下来,我们详细解析其他修正符: 1....

    php 中文和编码判断代码

    正则表达式例子中,提供了用于匹配GBK编码下可能包含中文字符的字符串的正则表达式,如使用`preg_replace`函数配合正则表达式来清除字符串中包含中文的字符。这些例子展示了如何在实际代码中应用这些规则。 在代码...

Global site tag (gtag.js) - Google Analytics