PHP中文字符串截断无乱码解决方法


Posted in PHP onOctober 10, 2016

一个比较好用的字符串截取函数:

function substring($str, $start, $length){ //比较好用字符串截取函数
  $len = $length;
  if($length < 0){
  $str = strrev($str);
  $len = -$length;
  }
  $len= ($len < strlen($str)) ? $len : strlen($str);
  $tmpstr = "";
  for ($i= $start; $i < $len; $i ++)
  {
      if (ord(substr($str, $i, 1)) > 0xa0)
      {
       $tmpstr .= substr($str, $i, 2);
       $i++;
      } else {
       $tmpstr .= substr($str, $i, 1);
      }
  }
  if($length < 0) $tmpstr = strrev($tmpstr);
  return $tmpstr;
}

使用方法示例:

$str1 = '我是一串比较长的中文不带英文';
$str2 = '我是一串比较长的中文带yingwen';


$len = strlen($str1);
echo '<br />'.$len; //return 28

$len = strlen($str2);
echo '<br />'.$len; //return 29

echo '<br />';  
echo substring($str1, 0, 11);  
echo '<br />';
echo substring($str2, 0, 11);    
echo '<br />';
echo substring($str1, 16, 28);  
echo '<br />';
echo substring($str2, 16, 29);

结果显示:

28
29
我是一串比较
我是一串比较
中文不带英文
中文带yingwen

这个函数十分有用,比如用来截断比较长的文件名,但是要在中间加上...,可以这样来做:

function formatName($str, $size){
  $len = strlen($str);
  if(strlen($str) > $size) {
    $part1 = substring($str, 0, $size / 2);
    $part2 = substring($str, $len - ($size/2), $len);
    return $part1 . "..." . $part2;
  } else {
    return $str;
  }
}

另外,网上看到一种超级简单的中文截断解决方案,试用了一下,效果也不错:

echo substr($str1,0,10).chr(0);

原理解释:

chr(0)不是null
07null是什么都没有,而chr(0)的值是0。表示成16进制是0x00,表示成二进制是00000000
08虽然chr(0)不会显示出什么,但是他是一个字符。
09当汉字被截断时,根据编码规则他总是要把后边的其他字符拉过来一起作为汉字解释,这就是出现乱码的原因。而值为0x81到0xff与0x00组合始终都显示为“空”
10根据这一特点,在substr的结果后面补上一个chr(0),就可以防止出现乱码了

----------------------------

20120705更新: 

以上方法虽好,但是偶尔还是会碰到乱码,原因未深究。不过可以用以下的方法,对UTF8字符文本屡试不爽。
注意:该方法中将汉字计算为1单位长度,英文一个字母1单位长度,所以截断时需要注意长度设置。
计算长度的方法:

function strlen_UTF8($str)
{
  $len = strlen($str);
  $n = 0;
  for($i = 0; $i < $len; $i++) {
    $x = substr($str, $i, 1);
    $a = base_convert(ord($x), 10, 2);
    $a = substr('00000000'.$a, -8);
    if (substr($a, 0, 1) == 0) {
    }elseif (substr($a, 0, 3) == 110) {
      $i += 1;
    }elseif (substr($a, 0, 4) == 1110) {
      $i += 2;
    }
    $n++;
  }
  return $n;
} // End strlen_UTF8;

字符串截断函数:

function subString_UTF8($str, $start, $lenth)
  {
    $len = strlen($str);
    $r = array();
    $n = 0;
    $m = 0;
    for($i = 0; $i < $len; $i++) {
      $x = substr($str, $i, 1);
      $a = base_convert(ord($x), 10, 2);
      $a = substr('00000000'.$a, -8);
      if ($n < $start){
        if (substr($a, 0, 1) == 0) {
        }elseif (substr($a, 0, 3) == 110) {
          $i += 1;
        }elseif (substr($a, 0, 4) == 1110) {
          $i += 2;
        }
        $n++;
      }else{
        if (substr($a, 0, 1) == 0) {
          $r[ ] = substr($str, $i, 1);
        }elseif (substr($a, 0, 3) == 110) {
          $r[ ] = substr($str, $i, 2);
          $i += 1;
        }elseif (substr($a, 0, 4) == 1110) {
          $r[ ] = substr($str, $i, 3);
          $i += 2;
        }else{
          $r[ ] = '';
        }
        if (++$m >= $lenth){
          break;
        }
      }
    }
    return join($r);
  } // End subString_UTF8;

使用方法和之前介绍的一样,比如formatName可以实现如下(这对汉字长度做了小优化):

function formatName($str, $size){
 $len = strlen_UTF8($str);
 $one_len = strlen($str);
 $size = $size * 1.5 * $len / ($one_len);
 if(strlen_UTF8($str) > $size) {
  $part1 = subString_UTF8($str, 0, $size / 2);
  $part2 = subString_UTF8($str, $len - ($size/2), $len);
  return $part1 . "..." . $part2;
 } else {
  return $str;
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
用DBSQL类加快开发MySQL数据库程序的速度
Oct 09 PHP
PHP 数组遍历顺序理解
Sep 09 PHP
PHP 学习路线与时间表
Feb 21 PHP
如何批量替换相对地址为绝对地址(利用bat批处理实现)
May 27 PHP
解析thinkphp import 文件内容变量失效的问题
Jun 20 PHP
9个经典的PHP代码片段分享
Dec 18 PHP
php+mysqli实现批量替换数据库表前缀的方法
Dec 29 PHP
php输出指定时间以前时间格式的方法
Mar 21 PHP
Nginx服务器上安装并配置PHPMyAdmin的教程
Aug 18 PHP
thinkPHP框架可添加js事件的分页类customPage.class.php完整实例
Mar 16 PHP
php实现和c#一致的DES加密解密实例
Jul 24 PHP
PHP实现腾讯与百度坐标转换
Aug 05 PHP
PHP获取用户客户端真实IP的解决方案
Oct 10 #PHP
php表单加入Token防止重复提交的方法分析
Oct 10 #PHP
Laravel5中防止XSS跨站攻击的方法
Oct 10 #PHP
php中让人头疼的浮点数运算分析
Oct 10 #PHP
Laravel实现自定义错误输出内容的方法
Oct 10 #PHP
PHP定时任务获取微信access_token的方法
Oct 10 #PHP
php使用SAE原生Mail类实现各种类型邮件发送的方法
Oct 10 #PHP
You might like
如何开始收听短波广播
2021/03/01 无线电
PHP APC缓存配置、使用详解
2014/03/06 PHP
destoon实现不同会员组公司名称显示不同的颜色的方法
2014/08/22 PHP
Ubuntu 16.04下安装PHP 7过程详解
2017/03/28 PHP
PHP7中I/O模型内核剖析详解
2019/04/14 PHP
Dom 结点创建 基础知识
2011/10/01 Javascript
限制textbox或textarea输入字符长度的JS代码
2013/10/16 Javascript
Javascript自定义函数判断网站访问类型是PC还是移动终端
2014/01/10 Javascript
JS使用ajax方法获取指定url的head信息中指定字段值的方法
2015/03/24 Javascript
JavaScript运算符小结
2015/06/03 Javascript
javascript实现网站加入收藏功能
2015/12/16 Javascript
JavaScript 正则表达式中global模式的特性
2016/02/25 Javascript
基于Javascript实现返回顶部按钮
2016/02/29 Javascript
jQuery实现的多滑动门,多选项卡效果代码
2016/03/28 Javascript
AngularJS框架的ng-app指令与自动加载实现方法分析
2017/01/04 Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
2018/01/18 Javascript
js中的 || 与 &amp;&amp; 运算符详解
2018/05/24 Javascript
react 兄弟组件如何调用对方的方法示例
2018/10/23 Javascript
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
在vue项目中使用sass语法问题
2019/07/18 Javascript
layui-select动态选中值的例子
2019/09/23 Javascript
python登录QQ邮箱发信的实现代码
2013/02/10 Python
在Python中利用Into包整洁地进行数据迁移的教程
2015/03/30 Python
Python中的面向对象编程详解(下)
2015/04/13 Python
使用Python完成15位18位身份证的互转功能
2019/11/06 Python
关于torch.optim的灵活使用详解(包括重写SGD,加上L1正则)
2020/02/20 Python
python中导入 train_test_split提示错误的解决
2020/06/19 Python
Python容器类型公共方法总结
2020/08/19 Python
北美最大的手工艺品零售商之一:Michaels Stores
2019/02/27 全球购物
Structs界面控制层技术
2013/10/11 面试题
宾馆总经理岗位职责
2014/02/14 职场文书
交通事故协议书范本
2014/11/18 职场文书
工作违纪检讨书范文
2015/01/26 职场文书
奖学金主要事迹范文
2015/11/04 职场文书
判断Python中的Nonetype类型
2021/05/25 Python
海康机器人重磅发布全新算法开发平台VM4.2
2022/04/21 数码科技