今天遇到一个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";