PHP就有函数实现字符串截取substr,mb_substr,mb_strimwidth
1.substr遇到中文可能就会乱码,因为1个中文字符占3个位(指占3个字母的长度)
2.mb_substr可以截取中文字符串,不过截取出来的宽度不一样(2个字母占一个中文字符的宽度)
3.mb_strimwidth这个函数我使用起来总觉得不对劲,width为什么要+3才能开始截取?如果width写太少它就会乱取
以上种种问题,我就想自己写个函数,解决字符串不会乱码,宽度不会有偏差。
1.第一个问题,substr会乱码,我看过emlog有个函数解决了这个问题,大致是截取后算出其中包含的中文字符长度,因为中文字符占3位,缺少几位就补几位就可以。
/**
* 截取编码为utf8的字符串
*
* @param string $strings 预处理字符串
* @param int $start 开始处 eg:0
* @param int $length 截取长度
*/
function subString($strings, $start, $length) {
if (function_exists('mb_substr') && function_exists('mb_strlen')) {
$sub_str = mb_substr($strings, $start, $length, 'utf8');
return mb_strlen($sub_str, 'utf8') < mb_strlen($strings, 'utf8') ? $sub_str . '...' : $sub_str;
}
$str = substr($strings, $start, $length);
$char = 0;
for ($i = 0; $i < strlen($str); $i++) {
if (ord($str[$i]) >= 128)
$char++;
}
$str2 = substr($strings, $start, $length + 1);
$str3 = substr($strings, $start, $length + 2);
if ($char % 3 == 1) {
if ($length <= strlen($strings)) {
$str3 = $str3 .= '...';
}
return $str3;
}
if ($char % 3 == 2) {
if ($length <= strlen($strings)) {
$str2 = $str2 .= '...';
}
return $str2;
}
if ($char % 3 == 0) {
if ($length <= strlen($strings)) {
$str = $str .= '...';
}
return $str;
}
}
// 自己写的带有注释函数(上面函数式是从emlog复制过来的)
// 其实把有mb_*的函数,就没必要自己写这个函数了,写这个函数只是为了兼容没有mb_*函数时(就像ci里面,core/compare里面会有一些其它版本的兼容函数)
function str_limit($string, $start, $length)
{
$str = substr($string, $start, $length);
// 应该是计算出中文字符长度(可能是ord出>=128就是中文字符的一部分,这里注意1个中文字符占3位)
$char = 0;
for ($i = 0; $i < $length; $i++) {
if (ord($str[$i]) >= 128) {
$char++;
}
}
// 由于中文字符是占3位,那么截取出来的可能是1位都不缺,或者缺1位,或者缺2位
$str1 = substr($string, $start, $length + 1);
$str2 = substr($string, $start, $length + 2);
if ($char %3 == 0) {
if ($length <= strlen($string)) {
$str .= '...';
}
return $str;
}
if ($char % 3 == 1){
if ($length <= strlen($string)) {
$str2 .= '...';
}
return $str2;
}
if ($char % 3 == 2){
if ($length <= strlen($string)) {
$str1 .= '...';
}
return $str1;
}
}
var_dump(str_limit("nihao你好呀的重庆", 0, 10));
// 解决中英文字符串截取宽度问题
// (用法 str_limit($string, 2*x, '...')其中2表示一个中文字符的长度,也就是说以中文字符长度为准)
function str_limit($string, $length, $end = '...')
{
// 已经截取的字符串
$str = '';
// 已经截取到的长度
$len = 0;
// 计算最后1个中文字符已经截取到第几位了
$endLen = 0;
// 被截取字符串的长度
$strLen = strlen($string);
// 循环字符串长度去截取
for ($i = 0; $i < $strLen; $i++) {
// 没有字符串可截取就跳出去
if (!isset($string[$i])) {
break;
}
// 如果已经截取完成(中文字符可能直接进2位,所以这里要写>=号)
if ($len >= $length) {
break;
}
// 把截取到字符拼接到另一个变量,计算该字符是中文字还是英文字,如果是中文字需截取到3位才能算2个长度(也就是说最后1个字符的长度可能超出了预料的长度)
$str .= $string[$i];
if (ord($string[$i]) >= 128) {
$endLen++;
if ($endLen == 3) {
$len += 2;
$endLen = 0;
}
} else {
$len++;
}
}
// 上面截取最后1个字符可能超出预算,因为最后1个字符可能是中文
// 所以最多超出2个位(3位表示1个中文字符),1个中文字符等于2个字母长度,误差也就是1个字母长度
// 这里也就没必去为了整个长度就1个字母长度的误差,再次计算,性能不划算(后面有时间看看再怎么优化把,其实已经满足现在的需求了,有取就有舍的道理,如反过来想,如果截取的最后一个字符是中文,那么原本却只要1的字母的长度,那么最后一个中文字符就得丢掉,也就会丢一个字母长度)
// 处理被截取的字符串长度 大于 截取的长度,后面拼接...
if (isset($string[$i + 1])) {
$str .= $end;
}
return $str;
}
- Prev: MySQL 5.7 开启查询日志
- Next: a-z 字母累增排号