PHP的trim和preg_replace导致乱码的问题及解决

trim问题发现

某天,线上展示的数据,发现多了问号,一排查,上游数据里多了0xC2和0xA0,百度查了一下,说是UTF8格式的空格,对应 网页里的 这个东东。
ok,问题找到了,简单对数据做一个trim就好了嘛,于是代码改成:

$name = trim($name, chr(0xc2) . chr(0xa0));

嗯,这么简单的代码还测试啥,上线吧!
结果,当天就有负责审核的同学找来了,怎么数据都会少字啊,比如漫画变成了漫,画字不见了……

var_dump(trim('平安普惠', chr(0xc2) . chr(0xa0)));
// 打印结果是 平安普,少了一个惠字

查了一下资料,原来php默认不能正确处理多字节字符,比如中文,如果要处理中文,要用mb_开头的函数,参考:http://php.net/manual/zh/ref.mbstring.php
可是,问题来了,没有 mb_trim这样的函数啊啊啊!
还好,上面的页面里也给了解决方案,用正则+utf8模式代替,嗯,php官方参考页面有其它用户提供了解决方案:

function mb_trim($string, $trim_chars = '\s'){
    return preg_replace('/^['.$trim_chars.']*(?U)(.*)['.$trim_chars.']*$/u', '\\1',$string);
}

好吧,我稍微优化了一下,变成:

function mb_trim($string){
    return preg_replace('/(^\s*)|(\s*$)/u', '', $string);
}

这回不能盲目上线了,对库中400万的数据遍历测试了一轮,果然出问题了,

$str = '破千魂';
$str2 = mb_trim($str);
var_dump($str2); // str2变成了NULL

查了半天资料,没有结论,后面想到\s*,即使没有空格也会进行替换,效率不好,改成\s+,结果就ok了,汗,最终的mb_trim函数定义如下:

function mb_trim($string){
    // u模式符表示 字符串被当成 UTF-8处理
    return preg_replace('/(^\s+)|(\s+$)/u', '', $string);
}

后语,为啥\s*会出错呢?偶然发现在php5.2版本上,\s*也能正常工作,hhvm下也是正常的,
再看我出问题的php,是5.4.33,赶紧去官网重新下载了一个5.4.45(php5.4最后一个版本),编译并测试后,发现结果也是正常的,重新下载5.4.33编译,问题依旧,
至此,确认那是php5.4.33的一个bug了,不过最后那个版本的mb_trim还是能正常工作的。
记录下来。

猜你喜欢

转载自blog.csdn.net/youbl/article/details/77854736