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 相关文章推荐
php中神奇的fastcgi_finish_request
May 02 PHP
PHP递归调用的小技巧讲解
Feb 19 PHP
PHP CURL CURLOPT参数说明(curl_setopt)
Sep 30 PHP
使用php验证复选框有效性的示例
Nov 13 PHP
PHP使用GIFEncoder类生成gif动态滚动字幕
Jul 01 PHP
ThinkPHP 表单自动验证运用示例
Oct 13 PHP
PHP使用缓存即时输出内容(output buffering)的方法
Aug 03 PHP
PHP的几个常用加密函数
Feb 03 PHP
PHP+HTML+JavaScript+Css实现简单爬虫开发
Mar 28 PHP
php实现水印文字和缩略图的方法示例
Dec 29 PHP
php判断str字符串是否是xml格式数据的方法示例
Jul 26 PHP
Laravel5.1框架注册中间件的三种场景详解
Jul 09 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
smarty的保留变量问题
2008/10/23 PHP
深入for,while,foreach遍历时间比较的详解
2013/06/08 PHP
CI框架学习笔记(二) -入口文件index.php
2014/10/27 PHP
新浪SAE搭建PHP项目教程
2015/01/28 PHP
phpinfo无法显示的原因及解决办法
2019/02/15 PHP
laravel5.5安装jwt-auth 生成token令牌的示例
2019/10/24 PHP
js判断上传文件类型判断FileUpload文件类型代码
2014/05/20 Javascript
JavaScript中textRange对象使用方法小结
2015/03/24 Javascript
详解AngularJS中自定义过滤器
2015/12/28 Javascript
JavaScript获取对象在页面中位置坐标的方法
2016/02/03 Javascript
Javascript 实现计算器时间功能详解及实例(二)
2017/01/08 Javascript
AngularJS 防止页面闪烁的方法
2017/03/09 Javascript
如何阻止小程序遮罩层下方图层滚动
2019/09/05 Javascript
三步实现ionic3点击退出app程序
2019/09/17 Javascript
VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)
2020/04/03 Javascript
[43:33]EG vs Spirit Supermajor 败者组 BO3 第一场 6.4
2018/06/05 DOTA
python批量修改文件后缀示例代码分享
2013/12/24 Python
零基础写python爬虫之抓取百度贴吧代码分享
2014/11/06 Python
Python实现判断一个字符串是否包含子串的方法总结
2017/11/21 Python
ubuntu16.04制作vim和python3的开发环境
2018/09/23 Python
完美解决python3.7 pip升级 拒绝访问问题
2019/07/12 Python
django项目用higcharts统计最近七天文章点击量
2019/08/17 Python
Python的bit_length函数来二进制的位数方法
2019/08/27 Python
Python 闭包,函数分隔作用域,nonlocal声明非局部变量操作示例
2019/10/14 Python
深入理解Python 多线程
2020/06/16 Python
利用PyQt5+Matplotlib 绘制静态/动态图的实现代码
2020/07/13 Python
*p++ 自增p 还是p所指向的变量
2016/07/16 面试题
什么是唯一索引
2015/07/05 面试题
nohup的用法
2014/08/10 面试题
解释i节点在文件系统中的作用
2013/11/26 面试题
鞋类设计与工艺专业销售求职信
2013/11/01 职场文书
计算机专业求职信
2014/06/02 职场文书
2014年财务工作自我评价
2014/09/23 职场文书
工作收入住址证明
2014/10/28 职场文书
学校中层领导培训心得体会
2016/01/11 职场文书
小学数学新课改心得体会
2016/01/22 职场文书