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