日期:2014-05-17  浏览次数:20426 次

php 中文字符串截取问题???
因为用substr()函数截取中文字符串会出现问题,所以我就上网找了一个函数,如下:
PHP code
//中文字符串截取无乱码函数
function cut_str($string, $start, $length) {
   if(strlen($string)>$length){
      $str = null;
      $len = $start+$length;
      for($i=$start;$i<$len;$i++){
        if(ord(substr($string,$i,1))>0xa0){
           $str.=substr($string,$i,2);
           $i++;
        }else{ 
           $str.=substr($string,$i,1);
  
        }
   }
        return $str.'...';
   }else{
        return $string;
   }
}    


但是用过之后还是会出现问题,比如我截取的是“利用滤镜及图层样式制作逼真的石块字”,
PHP code

$str = "利用滤镜及图层样式制作逼真的石块字";
cut_str($str,0,50);



但是效果出来了却是这样的:“利用滤镜及图层样式制作逼真的石块?...”,除了个问号一样的字符,我郁闷啊,上网查了一下,汉子在utf-8编码中一般占3个字节,但是这个函数中这里“$str.=substr($string,$i,2);”却截取2,这是什么意思呢??始终没有弄明啊。。。。如果我把2改成3后,那句就会变成“利?甔?滻??镜?及?图?山??样?弼??制?佽??逼?眜?的?石?坝?字...”,唉,,,真的被它搞败了,哪位大侠救救我啊。。。。。。。。。

------解决方案--------------------
怎么不用mb_substr()函数
------解决方案--------------------
你要确定你的编码。截取时指定编码。
------解决方案--------------------
它是以字节计算的。gbk编码。一个中文等于2个字节。
------解决方案--------------------
当然是mb_substr了,楼主对编码看样不太懂。。。

utf8中文编码2-3个字符很常见,但非ASCII字符的单字节一定是第7位为1的,与ASCII单字节是不冲突的,GBK码也是类似的。

请用mb_substr,它会自动根据utf8编码范围识别多字节字符的。
------解决方案--------------------
这个函数只适用于gbk编码

探讨

哈哈,研究了下手册,刚搞定,就是你说的,确定一下编码,但是我想知道那个函数为啥不行啊??那个貌似是php面试的答案诶。前辈能否指点一二,特别是那里的2,utf-8中汉子明明是3-4个字符啊,而且常用的是3个字符啊。。。。。麻烦了

------解决方案--------------------
PHP code

/****************************
 * subCNchar() 截取汉字 *
 * [$str]     [要截取的字符串]
 * [$start]   [截取的起始位置]
 * [$length]  [要截取的长度]
 * [$charset] [字符串编码]
 ****************************/
function subCNchar($str, $start = 0, $length, $charset = "utf-8") {
    if (strlen($str) <= $length)
        return $str;

    $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
    $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
    $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
    $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
    preg_match_all($re[$charset], $str, $match);

    $slice = join("", array_slice($match[0], $start, $length));

    return $slice;
}

------解决方案--------------------
为什么不能在后面加上.....
echo mb_strlen($str,'utf-8')>10 ? mb_substr($str,0,10,'utf-8').'...' : $str;
------解决方案--------------------
加"..."见12楼, 

如果你非要改这个函数,utf8的编码很有规律,就是下面几种,除ascii码部分外,
第一个字节都是11开头,连续的1的个数代表了总字节数,后续字节都是10开头
其中汉字基本在3个字节的区. 
知道了这个规律,写个函数应该很容易吧?
U+007F 0xxxxxxx
U+07FF 110xxxxx 10xxxxxx
U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U+3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx



探讨

那这个函数能不能改成utf-8的??mb_substr()貌似不能在未输出完的字符结尾加上“...”诶,这样影响效果,求解

------解决方案--------------------
你可以用mb_strimwidth函数