从一个bug谈rtrim

来源:互联网 发布:用java编写atm取款机 编辑:程序博客网 时间:2024/05/15 05:51

今天遇到一个bug,代码很简单:

<?php$src = '战争片';$result = rtrim($src, '片');echo mb_convert_encoding($result, 'gbk', 'utf-8'),"\n";
本来以为得到的结果会是“战争”,但实际输出的却只有“战”。
不明所以,以为是rtrim的问题。查了一下,原来是自己对rtrim的理解有误。

rtrim函数原型:string rtrim ( string str [, string charlist] )
仔细看了下手册中charlist的解释:
You can also specify the characters you want to strip, by means of the charlist parameter. Simply list all characters that you want to be stripped.
它的实际意思应该是:以每个字符为单位从目标字符串的右端开始查找,如果该字符在trim函数的第二个参数中,就将其删掉,直到当前字符不在参数列表中为止。而并非是我先前以为的:从str的串尾去掉固定字串charlist。

用一个例子具体说明:

<?php$src = 'test.rtrim';$rtrimList = 'trim';$result = rtrim($src, $rtrimList);echo $result, "\n";
rtrim做的工作是:从$src中取出最后一个字符“m”,发现“m”在$rtrimList中,于是去掉;再取出“i”,发现“i”也在$rtrimList中,也去掉,...依次向左,直到进行到“.”,发现“.”不在$rtrimList中,于是停止工作。因此最终我们得到的$result是“test.”,而非“test.r”。

至于本文开头的例子,当然也是因为这个原因导致的错误了。

<?php$src = '战争片';echo rawurlencode($src), "\n";
得到结果:
%E6%88%98
%E4%BA%89%E7%89%87
可见“片”的编码(utf8)是E7 89 87三个字符,因此trim工作时,除了去掉了“片”,还将“争”字最后的89去掉了!因此,“争”是不完整的,mb_convert_encoding时被去掉了。

解决:

<?php$src = '战争片';$result = preg_replace('/片$/', '', $src);echo mb_convert_encoding($result, 'gbk', 'utf-8'),"\n";