PHP 內建 substr() 函數按位元組截取字串,對於多位元組編碼(UTF-8 中文佔 3 位元組、Big5 佔 2 位元組)會導致中文字元被切斷,產生亂碼。本文詳細分析問題成因,提供多種解決方案。
$str = "你好世界 Hello World"; // 正確截取前 6 個字元(包含中英文) $result = mb_substr($str, 0, 6, 'UTF-8'); // 結果:"你好世界" echo mb_substr($str, 0, 10, 'UTF-8'); // "你好世界 Hello"
優點:原生支援、效能佳、語法簡單
前提:PHP 需安裝 mbstring 擴充(現代環境通常預設啟用)
function utf8_substr($str, $start, $length) {
$result = '';
$strLen = strlen($str);
$charCount = 0;
$bytePos = 0;
for ($i = 0; $i < $strLen; $i++) {
$byte = ord($str[$i]);
// 判斷 UTF-8 字元位元組數
if ($byte < 0x80) {
$charBytes = 1; // 0xxxxxxx (ASCII)
} elseif ($byte < 0xE0) {
$charBytes = 2; // 110xxxxx 10xxxxxx
} elseif ($byte < 0xF0) {
$charBytes = 3; // 1110xxxx 10xxxxxx 10xxxxxx (中文)
} else {
$charBytes = 4; // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
}
if ($charCount >= $start && $charCount < $start + $length) {
$result .= substr($str, $i, $charBytes);
}
$charCount++;
$i += $charBytes - 1; // 跳過後續位元組
}
return $result;
}
function mb_substr_alt($str, $start, $length) {
$chars = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
return implode('', array_slice($chars, $start, $length));
}
| 方法 | 效能 | 相依性 | 建議場景 |
|---|---|---|---|
| mb_substr() | 最高 | mbstring | 生產環境首選 |
| 自訂位元組解析 | 中等 | 無 | 無 mbstring 環境 |
| preg_split 方案 | 較低 | PCRE | 快速原型、短字串 |
function generateExcerpt($content, $length = 200) {
// 移除 HTML 標籤
$text = strip_tags($content);
// 正確截取
$excerpt = mb_substr($text, 0, $length, 'UTF-8');
// 若有截斷,加上省略號
if (mb_strlen($text, 'UTF-8') > $length) {
$excerpt .= '...';
}
return $excerpt;
}
掌握多位元組字串處理,是 PHP 開發中文應用的基礎功力。建議專案統一使用 mb_* 系列函數,並設定 mb_internal_encoding('UTF-8') 避免重複指定編碼參數。