php实现过滤中英文标点符号[gbk编码环境]
2017-08-05 19:31
302 查看
因项目需求需要对帖子标题做去重判断,前提是去除所有中英文标点符号。因为是老项目,gbk编码,在直接使用正则匹配去除标点符号时,发现会有乱码情况。在网上找了一些处理方法,多多少少都有些问题,满足不了我的需求。但也受到了些许启发,开始写了一个实现方法,有些麻烦,需要urlencode。
后来,看了鸟哥的一篇博客【分割GBK中文遭遇乱码的解决】,顿悟的赶脚,因此优化如下:
若不仅想去掉标点符号,还想去掉扩充非汉字,如:ˊ ˋ ˙ – ― ‥ ‵ ℅ ℉ ↖ ↗ ↘ ↙ ∕ ∟ ∣等,修改如下:
近日又发现些问题,会有中文被替换后乱码的情况,比如“本楼盘有特价单位推出!开发商内部价格!找小邹买房有优惠!”使用上述方法替换后结果为“本绿有特价祷推出开诽内部价格找修买房有优惠”
究其原因,直接用preg_replace()匹配时,会出现类似如下情况:
已知“楼盘”两个字的gbk字符编码为
使用正则
最终结果表现为“楼盘”替换成了“绿”字
因此最终决定一个字一个字的匹配处理,本人项目中标题为50字以内,因此循环处理还可以接受,若需要处理字符串较长,还是另寻他法吧。
欢迎指正补充。
gbk编码分两部分,一部分是单字节编码,另一部分是双字节编码。
gbk编码中,前128个编码都是单字节编码。单字节编码从00-7F,与ASCII相对应。
在单字节编码之后就是双字节编码。第一个字节范围是81-FE。第二字节的一部分领域在40–7E,其他领域在80–FE。
这样可以通过第一个字节就可以判断是单字节编码还是双字节编码。
摘录自GBK编码表与编码字库
双字节编码区又分为5部分
GBK汉字内码扩展规范编码表
可参考博客GBK汉字内码扩展规范编码表
/** * 去除字符串中的标点符号[gbk编码环境] * @param $str * @return string */ function punctFilter($str){ //先去掉英文标点符号、空格等 $str = preg_replace('/[[:punct:]\s\n\t\r]/','',$str); //再匹配中文标点符号 直接进行中文标点符号匹配会乱码,因此先编码后匹配。 //若以下标点还满足不了需要,可搜索中文gbk编码表,将对应标点符号加上即可。 $pattern = '/(%a1%a0|%a1%a1|%a1%a2|%a1%a3|%a1%a4|%a1%a5|%a1%a6|%a1%a7|%a1%a8|%a1%a9|%a1%aa|%a1%ab|%a1%ac|%a1%ad|%a1%ae|%a1%af|%a1%b0|%a1%b1|%a1%b2|%a1%b3|%a1%b4|%a1%b5|%a1%b6|%a1%b7|%a1%b8|%a1%b9|%a1%ba|%a1%bb|%a1%bc|%a1%bd|%a1%be|%a1%bf|%a1%c0|%a1%c1|%a1%c2|%a1%c3|%a1%c4|%a1%c5|%a1%c6|%a1%c7|%a1%c8|%a1%c9|%a1%ca|%a1%cb|%a1%cc|%a1%cd|%a1%ce|%a1%cf|%a1%d0|%a1%d1|%a1%d2|%a1%d3|%a1%d4|%a1%d5|%a1%d6|%a1%d7|%a1%d8|%a1%d9|%a1%da|%a1%db|%a1%dc|%a1%dd|%a1%de|%a1%df|%a1%e0|%a1%e1|%a1%e2|%a1%e3|%a1%e4|%a1%e5|%a1%e6|%a1%e7|%a1%e8|%a1%e9|%a1%ea|%a1%eb|%a1%ec|%a1%ed|%a1%ee|%a1%ef|%a1%f0|%a1%f1|%a1%f2|%a1%f3|%a1%f4|%a1%f5|%a1%f6|%a1%f7|%a1%f8|%a1%f9|%a1%fa|%a1%fb|%a1%fc|%a1%fd|%a3%a0|%a3%a1|%a3%a2|%a3%a3|%a3%a4|%a3%a5|%a3%a6|%a3%a7|%a3%a8|%a3%a9|%a3%aa|%a3%ab|%a3%ac|%a3%ad|%a3%ae|%a3%ba|%a3%bb|%a3%bc|%a3%bd|%a3%be|%a3%bf|%a3%c0|%a3%db|%a3%dc|%a3%dd|%a3%de|%a3%df|%a3%e0|%a3%fb|%a3%fc|%a3%fd|%a3%fe|%a3%ff)/iu'; $str = preg_replace($pattern, '', urlencode($str)); return urldecode($str); } //使用示例 $str = '和≦哈1;!eo-\'\'?-+$*()‘’""“”[]-、ヾ嘿【哈】'; var_dump('punctFilter($str)',punctFilter($str)); //结果为:和≦哈1eoヾ嘿哈
后来,看了鸟哥的一篇博客【分割GBK中文遭遇乱码的解决】,顿悟的赶脚,因此优化如下:
/** * 去除字符串中的标点符号[gbk编码环境](废弃,看下面说明) * @param $str * @return string */ function punctFilter($str){ //先去掉英文标点符号、空格等 $str = preg_replace('/[[:punct:]\s\n\t\r]/','',$str); //再匹配中文标点符号 //第1字节:A1–A9 第2字节:A1–FE GB2312非汉字符号 return preg_replace('/([\xa1-\xa9][\xa1-\xfe])+/', '', $str); } //使用示例 $str = '和≦哈1;!eo-\'\'?-+$*()‘’""“”[]-、ヾ嘿【哈】'; var_dump(punctFilter($str)); //结果为:和≦哈1eoヾ嘿哈
若不仅想去掉标点符号,还想去掉扩充非汉字,如:ˊ ˋ ˙ – ― ‥ ‵ ℅ ℉ ↖ ↗ ↘ ↙ ∕ ∟ ∣等,修改如下:
/** * 去除字符串中的标点符号[gbk编码环境](废弃,看下面说明) * @param $str * @return string */ function punctFilter($str){ //先去掉英文标点符号、空格等 $str = preg_replace('/[[:punct:]\s\n\t\r]/','',$str); //再匹配中文标点符号 //第1字节:A1–A9 第2字节:A1–FE GB2312非汉字符号 //第1字节:A8–A9 第2字节:40–A0(7F除外) 扩充非汉字 return preg_replace('/(([\xa1-\xa9][\xa1-\xfe])|([\xa8-\xa9][\x40-\xa0]))+/', '', $str); } //使用示例 $str = '和≦哈1;!eo-\'\'?-+$*()‘’""“”[]-、ヾ嘿【哈】'; var_dump(punctFilter($str)); //结果为:和哈1eo嘿哈
近日又发现些问题,会有中文被替换后乱码的情况,比如“本楼盘有特价单位推出!开发商内部价格!找小邹买房有优惠!”使用上述方法替换后结果为“本绿有特价祷推出开诽内部价格找修买房有优惠”
究其原因,直接用preg_replace()匹配时,会出现类似如下情况:
已知“楼盘”两个字的gbk字符编码为
c2a5c5cc
使用正则
(/([\xa1-\xa9][\xa1-\xfe])+/)替换时,会将
a5c5替换掉,只留下
c2cc
最终结果表现为“楼盘”替换成了“绿”字
因此最终决定一个字一个字的匹配处理,本人项目中标题为50字以内,因此循环处理还可以接受,若需要处理字符串较长,还是另寻他法吧。
/** * 去除字符串中的标点符号 * @param $str * @return string */ function punctFilter($str){ //先去掉英文标点符号、空格等 $str = preg_replace('/[[:punct:]\s\n\t\r]/','',$str); //再匹配中文标点符号 $len = mb_strlen($str,'gbk'); $newstr = $str; for($i = 0; $i < $len; $i++){ $substr = mb_substr($str,$i,1,'gbk'); //第1字节:A1-A9 第2字节:A1-FE 非汉字符号 if(preg_match('/([\xa1-\xa9][\xa1-\xfe])+/', $substr,$match)){ $newstr = str_replace($substr, '', $newstr); } } return $newstr; } //使用示例 $str = '和≦哈1;!eo-\'\'?-+$*()‘’""“”[]-、ヾ嘿【哈】'; var_dump(punctFilter($str)); //结果为:和≦哈1eoヾ嘿哈 //使用示例 $str = '本楼盘有特价单位推出!开发商内部价格!找小邹买房有优惠!'; var_dump(punctFilter($str)); //结果为:本楼盘有特价单位推出开发商内部价格找小邹买房有优惠
欢迎指正补充。
补充知识:
GBK编码的单字节与双字节gbk编码分两部分,一部分是单字节编码,另一部分是双字节编码。
gbk编码中,前128个编码都是单字节编码。单字节编码从00-7F,与ASCII相对应。
在单字节编码之后就是双字节编码。第一个字节范围是81-FE。第二字节的一部分领域在40–7E,其他领域在80–FE。
这样可以通过第一个字节就可以判断是单字节编码还是双字节编码。
摘录自GBK编码表与编码字库
双字节编码区又分为5部分
范围 | 第1字节 | 第2字节 | 编码数 | 字数 | 内容 |
---|---|---|---|---|---|
GBK/1 | A1–A9 | A1–FE | 846 | 717 | GB2312 |
GBK/2 | B0–F7 | A1–FE | 6,768 | 6,763 | GB2312汉字 |
GBK/3 | 81–A0 | 40–FE(7F除外) | 6,080 | 6,080 | 扩充汉字 |
GBK/4 | AA–FE | 40–A0(7F除外) | 8,160 | 8,160 | 扩充汉字 |
GBK/5 | A8–A9 | 40–A0(7F除外) | 192 | 166 | 扩充非汉字 |
用户定义 | AA–AF | A1–FE | 564 | ||
用户定义 | F8–FE | A1–FE | 658 | ||
用户定义 | A1–A7 | 40–A0(7F除外) | 672 |
可参考博客GBK汉字内码扩展规范编码表
相关文章推荐
- php实现gbk和uft8编码中英文字符截取函数的应用
- PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
- php实现gbk和uft8编码中英文字符截取函数的应用
- php截取字符串之截取utf8或gbk编码的中英文字符串示例
- php截取字符串之截取utf8或gbk编码的中英文字符串示例
- Sublime Text 2/3如何支持中文GBK编码(亲测实现)
- php 实现 过滤国家ip访问功能
- PHP关于GBK格式写入utf8_general_ci 编码mysql数据库乱码的解决办法
- [转载]敏感词过滤,PHP实现的Trie树
- PHP通过header和meta实现页面编码声明
- PHP转换编码问题GBK/UTF-8
- PHP写入WRITE编码为UTF8的文件的实现代码
- (原创)PHP利用iconv()函数实现任何编码之间的转换
- PHP数据库编程③基于mysql的在线词典案例(只实现中英文互查)
- php判断中英文请求,并实现跳转
- linux下安装配置Memcache和PHP环境的实现
- PHP中GBK和UTF8编码处理
- jsp Filter 实现编码过滤,和登录验证
- JavaScript PHP 通过URLEncode字串判断其编码是UTF-8还是GBK
- 下面哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换