找回密碼
 註冊
搜索
查看: 2381|回復: 3

[教學] php的substr截斷中文會出現截到半個漢字出現亂碼(修正版)

[複製鏈接]
發表於 2011-11-6 13:48:50 | 顯示全部樓層 |閱讀模式
 
Push to Facebook
現在可以使用mb_substr()函數安全的截取,後來看康盛的uchome,裡面有一個用代碼實現的getstr函數,寫得真好。拿下來了。
    tring substr ( string $string , int $start [, int $length ] )
    返回string中從start位置開始長度為length的字符串
substr函數在截取字符時是按字節來截取的,中文字符在GB2312編碼時為2個字節,utf-8編碼時為3個字節,所以截取指定長度的字符串時如果截斷了漢字,那麼返回的結果顯示出來便會出現亂碼。

以前的寫法會截到半個漢字
  1. function cutstr($string, $length, $dot = ' ...') {
  2.                 global $charset;
  3.                 if(strlen($string) <= $length) {
  4.                 return $string;
  5.                 }
  6.                 $string = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $string);
  7.                 $strcut = '';
  8.                 if(strtolower($charset) == 'utf-8') {
  9.                         $n = $tn = $noc = 0;
  10.                         while($n < strlen($string)) {
  11.                                 $t = ord($string[$n]);
  12.                                
  13.                                 if($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
  14.                                         $tn = 1; $n++; $noc++;
  15.                                 } elseif(194 <= $t && $t <= 223) {
  16.                                         $tn = 2; $n += 2; $noc += 2;
  17.                                 } elseif(224 <= $t && $t <= 239) {
  18.                                         $tn = 3; $n += 3; $noc += 2;
  19.                                 } elseif(240 <= $t && $t <= 247) {
  20.                                         $tn = 4; $n += 4; $noc += 2;
  21.                                 } elseif(248 <= $t && $t <= 251) {
  22.                                         $tn = 5; $n += 5; $noc += 2;
  23.                                 } elseif($t == 252 || $t == 253) {
  24.                                         $tn = 6; $n += 6; $noc += 2;
  25.                                 } else {
  26.                                         $n++;
  27.                                 }

  28.                                 if($noc >= $length) {
  29.                                 break;
  30.                                 }
  31.                         }
  32.                         if($noc > $length) {
  33.                                 $n -= $tn;
  34.                         }
  35.                         $strcut = substr($string, 0, $n);
  36.                 } else {
  37.                         for($i = 0; $i < $length; $i++) {
  38.                                 $strcut .= ord($string[$i]) > 127 ? $string[$i].$string[++$i] : $string[$i];
  39.                         }
  40.                 }
  41.                 $strcut = str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $strcut);
  42.         return $strcut.$dot;
  43.         }
複製代碼
解決辦法:
1、改用mb_substr()函數
    string mb_substr ( string $str , int $start [, int $length [, string $encoding ]] )
    類似substr()函數,只是計數按字符數來計,保證字符安全
使用mb_substr()函數可保證不會出現亂碼,但缺點是長度統計變成了字符數統計,而不是按字節數統計。用於顯示時,同樣長度的中文結果和英文結果會出現較大的顯示長度的差別。
2、來自康盛的substr功能
中文字符按2個長度單位來計算,使得中英文混用環境下字符串截取結果最後的顯示長度接近;捨棄最後一個不完整字符,保證不會出現顯示上的亂碼;且兼容了中文字符常用的utf-8編碼和GB2312編碼,有很好的通用性。

PHP代碼

  1. function getstr($string, $length, $encoding='utf-8') {   
  2.                   $string=trim($string);   
  3.                   if($length&&strlen($string)>$length) {   
  4.                   //截斷字符
  5.                     $wordscut = '';   
  6.                     if(strtolower($encoding)=='utf-8') {   
  7.                     //utf8編碼
  8.                               $n = 0;   
  9.                               $tn = 0;   
  10.                               $noc = 0;   
  11.                               while ($n < strlen($string)) {   
  12.                                 $t = ord($string[$n]);   
  13.                                 if($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {   
  14.                                           $tn = 1;   
  15.                                           $n++;   
  16.                                           $noc++;   
  17.                                 } elseif(194 <= $t && $t <= 223) {   
  18.                                           $tn = 2;   
  19.                                           $n += 2;   
  20.                                           $noc += 2;   
  21.                                        } elseif(224 <= $t && $t < 239) {   
  22.                                           $tn = 3;
  23.                                           $n += 3;
  24.                                           $noc += 2;   
  25.                                        } elseif(240 <= $t && $t <= 247) {   
  26.                                           $tn = 4;   
  27.                                           $n += 4;   
  28.                                           $noc += 2;   
  29.                                        } elseif(248 <= $t && $t <= 251) {   
  30.                                           $tn = 5;   
  31.                                           $n += 5;   
  32.                                           $noc += 2;   
  33.                                        } elseif($t == 252 || $t == 253) {   
  34.                                           $tn = 6;   
  35.                                           $n += 6;   
  36.                                           $noc += 2;   
  37.                                        } else {   
  38.                                           $n++;   
  39.                                        }   
  40.                                        if ($noc >= $length) {   
  41.                                          break;   
  42.                                        }   
  43.                              }
  44.                      if ($noc > $length) {   
  45.                                $n -= $tn;   
  46.                      }   
  47.                     $wordscut = substr($string, 0, $n);   
  48.                  } else {   
  49.                                for($i = 0; $i < $length - 1; $i++) {   
  50.                                         if(ord($string[$i]) > 127) {   
  51.                                            $wordscut .= $string[$i].$string[$i + 1];   
  52.                                            $i++;   
  53.                                 } else {   
  54.                                            $wordscut .= $string[$i];   
  55.                                 }
  56.                               }
  57.                     }   
  58.                     $string = $wordscut;     
  59.                 }   
  60.                           return trim($string);   
  61.         }
複製代碼

很強大的代碼。
 
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

Archiver|手機版|小黑屋|TShopping

GMT+8, 2025-6-17 16:00 , Processed in 0.021524 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回復 返回頂部 返回列表