PHP 內建 substr() 按位元組截取,對多位元組編碼(UTF-8、GBK、Big5)的中文會導致亂碼。本文提供兩個可直接使用的函數:mb_substr 封裝版(推薦)與純 PHP 實作版(無需 mbstring 擴展),均支援指定編碼、起始位置、長度、尾綴。
function mbCut($string, $start, $length, $charset = 'UTF-8', $suffix = '...') {
if (function_exists('mb_substr')) {
$slice = mb_substr($string, $start, $length, $charset);
return $suffix && mb_strlen($string, $charset) > $start + $length ? $slice . $suffix : $slice;
}
// fallback 見方案二
return selfCut($string, $start, $length, $charset, $suffix);
}
function selfCut($str, $start, $length, $charset = 'UTF-8', $suffix = '...') {
// 定義各編碼的字元正則
$patterns = [
'utf-8' => '/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/',
'gb2312' => '/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/',
'gbk' => '/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/',
'big5' => '/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/',
];
$charset = strtolower($charset);
if (!isset($patterns[$charset])) $charset = 'utf-8';
preg_match_all($patterns[$charset], $str, $matches);
$chars = $matches[0];
$slice = implode('', array_slice($chars, $start, $length));
if ($suffix && count($chars) > $start + $length) {
$slice .= $suffix;
}
return $slice;
}
function utf8SubstrManual($str, $start, $length) {
$len = strlen($str);
$result = [];
$count = 0;
$picked = 0;
for ($i = 0; $i < $len; $i++) {
$byte = $str[$i];
$ord = ord($byte);
$charLen = 1;
if (($ord & 0x80) == 0x00) $charLen = 1; // 0xxxxxxx
elseif (($ord & 0xE0) == 0xC0) $charLen = 2; // 110xxxxx
elseif (($ord & 0xF0) == 0xE0) $charLen = 3; // 1110xxxx
elseif (($ord & 0xF8) == 0xF0) $charLen = 4; // 11110xxx
if ($count >= $start && $picked < $length) {
$result[] = substr($str, $i, $charLen);
$picked++;
}
$count++;
$i += $charLen - 1;
}
return implode('', $result);
}
// 使用:join('', utf8SubstrManual($str, 0, 10));
$text = "PHP中文截取測試abcdefg";
// UTF-8 環境
echo mbCut($text, 0, 10); // PHP中文截取測試a...
echo selfCut($text, 0, 10, 'UTF-8'); // 同上
// GBK 環境(需確保檔案編碼為 GBK)
// echo selfCut($text, 0, 10, 'GBK');
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
mb_substr | 原生 C 實作、極快、支援所有編碼 | 需安裝 mbstring 擴展 | 現代 PHP 專案首選 |
正則 preg_match_all | 純 PHP、無擴展依賴 | 大字串效能較差、正則複雜 | 舊環境、共享主機無 mbstring |
| 手動位元組解析 | 邏輯清晰、教學價值高 | 效能最差、易出錯 | 學習 UTF-8 結構、極特殊環境 |
SET NAMES utf8mb4 確保讀寫一致。$length 皆為 字元數,非位元組數。