在很多网页展示中,标题的长度有时需要量身定制,比如已经排定好的样式,一般都不会满足太长的标题,这就需要对标题进行截取。考虑到一般都是中文、英文、数字、英文符号、中文符号混合的标题,现有的函数只能使用mb_substr这样的针对编码的截取方式。但是这样的结果总是不令人满意的。
比如,文章标题有以下几种:
1、全英文:Celine Dion My Love Ultimate Essential Collection My Heart Will Go On
2、全中文:一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十
3、中英文混排(包含中英标点):一二三四五;“;六七八九十;“;'Celine Dion My Love
这里使用mb_substr截取10字符将是什么效果?
Celine Dio
一二三四五六七八九十
一二三四五;“;六七
这种残次不齐的效果在网页中出现,迟早会被老板骂死~~~
针对这种定制样式截取,一般都是需要规定截取后字符的宽度像素的,也就是说,截取后的宽度一般等长的。研究一番发现一般英文两个字符相当于汉字一个字的占位空间。所以写下如下函数,解决这个问题。
<?PHP
function mb_sub($str,$len,$encode='utf8',$start=0){
if($encode!='utf8'){
$str = mb_convert_encoding($str,'utf8',$encode);
}
$osLen = mb_strlen($str);
if($osLen<=$len){
return $str;
}
$string = mb_substr($str,$start,$len,'utf8');
$sLen = mb_strlen($string,'utf8');
$bLen = strlen($string);
$sCharCount = (3*$sLen-$bLen)/2;
if($osLen<=$sCharCount+$len){
$arr = preg_split('/(?<!^)(?!$)/u',mb_substr($str,$len+1,$osLen,'utf8'));//将中英混合字符串分割成数组(UTF8下有效)
}else {
$arr = preg_split('/(?<!^)(?!$)/u',mb_substr($str,$len+1,$sCharCount,'utf8'));
}
foreach($arr as $value){
if(ord($value)<128 && ord($value)>0){
$sCharCount = $sCharCount-1;
}else {
$sCharCount = $sCharCount-2;
}
if($sCharCount<=0){
break;
}
$string.=$value;
}
return $string;
}
echo '一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十',"\n";
$str = '不是病猫!苹果Mountain Lion系统4天下载量破300万次';
echo mb_sub($str,17);
?>
函数中,为了适应多种编码,将编码均转换为utf8,演示效果如下