substr() 按字節截取,UTF-8 中文佔 3 字節、GBK 佔 2 字節,直接截取極易「鋸斷」多字節字符導致亂碼。本文詳細對比三種解決方案。
$str = '中國人'; echo substr($str, 0, 4); // UTF-8 輸出:中(第 4 字節屬於「國」第二字節)
需啟用 mbstring 擴展(php.ini 取消註釋 extension=mbstring)。
echo mb_substr('PHP中文字符', 0, 4, 'UTF-8'); // PHP中文(正確按字符計數)
echo mb_substr('PHP中文字符', 0, 4, 'GBK'); // 指定編碼
mb_check_encoding() 檢測echo iconv_substr($str, 0, 4, 'UTF-8');
行為與 mb_substr 類似,部分舊環境無 mbstring 但有 iconv 時可用。
function utf8_substr($str, $len) {
$result = '';
for ($i = 0; $i < $len; $i++) {
$char = $str[0];
$ord = ord($char);
if ($ord > 127) { // 多字節字符
$bytes = ($ord >= 0xF0) ? 4 : (($ord >= 0xE0) ? 3 : 2);
$result .= substr($str, 0, $bytes);
$str = substr($str, $bytes);
} else { // ASCII
$result .= $char;
$str = substr($str, 1);
}
}
return $result;
}
// 測試
echo utf8_substr('PHP中文字符', 4); // PHP中文
function sub_str($str, $length = 0, $append = true) {
$str = trim($str);
$strLen = strlen($str);
if ($length == 0 || $length >= $strLen) return $str;
if ($length < 0) {
$length = $strLen + $length;
if ($length < 0) $length = $strLen;
}
if (function_exists('mb_substr')) {
$newStr = mb_substr($str, 0, $length, 'UTF-8');
} elseif (function_exists('iconv_substr')) {
$newStr = iconv_substr($str, 0, $length, 'UTF-8');
} else {
$newStr = utf8_substr($str, $length); // 上述自定義函數
}
if ($append && $str !== $newStr) $newStr .= '...';
return $newStr;
}
function detect_encoding($str) {
$encodings = ['UTF-8', 'GBK', 'GB2312', 'BIG5'];
foreach ($encodings as $enc) {
if (mb_check_encoding($str, $enc)) return $enc;
}
return 'UTF-8'; // 預設
}
mb_substr:明確指定編碼參數,避免依賴 mbstring.internal_encodingtext-overflow: ellipsis 或 JS 處理| 函數 | 耗時 | 備註 |
|---|---|---|
mb_substr | ~0.45s | C 層實現,最快 |
iconv_substr | ~0.62s | 略慢 |
自定義 utf8_substr | ~2.1s | PHP 層循環,僅無擴展時用 |