前言
mb_substr() 是 substr() 的多位元組增強版,正確支援 UTF-8、Big5 等編碼,截取中文不會產生亂碼或半個字元。
核心差異:mb_substr vs mb_strcut
| 函式 | 單位 | 行為 | 範例結果 |
mb_substr($str, 0, 7, 'utf-8') | 字元 | 按「字」切割 | "這樣一來我的字" |
mb_strcut($str, 0, 6, 'utf-8') | 位元組 | 按「位元組」切割,不產生半字元 | "這樣" |
程式碼示範
<?php
$str = '這樣一來我的字符串就不會有亂碼^_^';
echo "mb_substr: " . mb_substr($str, 0, 7, 'utf-8') . "<br>";
// 結果:這樣一來我的字
echo "mb_strcut: " . mb_strcut($str, 0, 6, 'utf-8') . "<br>";
// 結果:這樣 (6 bytes = 2 中文字)
echo "mb_strlen: " . mb_strlen($str, 'utf-8') . "<br>";
// 結果:19 字元
?>
實務常用模式:超過長度自動截斷加省略號
<?php
function mb_truncate($str, $length = 20, $suffix = '...', $encoding = 'utf-8') {
if (mb_strlen($str, $encoding) <= $length) return $str;
return mb_substr($str, 0, $length, $encoding) . $suffix;
}
// 使用範例
$title = '這是一個非常非常長的標題需要被截斷顯示';
echo mb_truncate($title, 15); // 這是一個非常非常長的標...
?>
編碼參數對照表
| 編碼 | mb_substr 參數 | 適用場景 |
| UTF-8 | 'utf-8' 或 'UTF-8' | 現代網頁、資料庫、API 預設 |
| Big5 | 'big5' 或 'Big5' | 繁體中文舊系統、台灣政府資料 |
| GBK/GB2312 | 'gbk' 或 'GBK' | 簡體中文舊系統、大陸資料 |
| SJIS | 'sjis-win' | 日文系統 |
環境啟用檢查 (Windows)
- 確認
php_mbstring.dll 存在於 ext/ 目錄
- 複製至
C:\Windows\System32\ (舊版 PHP 需求)
- 編輯
php.ini:
;extension=php_mbstring.dll
→ extension=php_mbstring.dll
- 重啟 Web Server
- 驗證:
php -m | findstr mbstring 或 phpinfo() 搜尋 mbstring
常見陷阱與解決
| 問題 | 原因 | 解決 |
| 截取後顯示 或亂碼 | 編碼參數錯誤或未啟用 mbstring | 檢查 encoding 參數、確認 mbstring 已載入 |
| 長度計算不準 | 混用 strlen (byte) 與 mb_strlen (char) | 統一用 mb_strlen/mb_substr,指定 encoding |
| 英文數字也算 1 字元 | mb_strlen 視同 1 字元 | 需區分視覺寬度請用 mb_strwidth() |
| HTML 標籤被截斷 | 直接截取含 HTML 字串 | 先 strip_tags() 或用專門庫 (如 htmLawed) |
進階:視覺寬度截取 (中文=2、英文=1)
<?php
function mb_strimwidth_visual($str, $width = 40, $suffix = '...', $encoding = 'utf-8') {
// mb_strimwidth 以「寬度」計算:中文 2、英文 1
return mb_strimwidth($str, 0, $width, $suffix, $encoding);
}
$str = 'Hello世界Hello世界';
echo mb_strimwidth_visual($str, 20); // Hello世界Hello...
?>
現代框架整合範例 (Laravel Blade)
{{-- Blade 模板 --}}
<div class="truncate">{!! mb_truncate($article->title, 30) !!}</div>
{{-- 或使用 Laravel 內建 Str::limit (已支援多位元組) --}}
{{ Str::limit($article->title, 30) }}
效能提示
mb_substr 每次呼叫都會掃描字串,大量處理時建議先轉陣列:preg_split('//u', $str)
- 固定長度截取可用
mb_strcut (byte-based) 較快,但需確保不切中字元
- 避免在迴圈中重複呼叫
mb_strlen,先存變數
掌握 mb_substr、mb_strcut、mb_strlen、mb_strimwidth 四大函式,即能從容處理所有中文截取需求。