Smarty 內建 truncate 不支援中文多位元組字元,直接使用會導致亂碼。本文完整教學開發 truncate_cn 修飾器外掛,支援中英文混排精準截取。
| 項目 | 說明 |
|---|---|
| 外掛類型 | function、modifier、block、compiler、prefilter、postfilter、outputfilter、resource、insert |
| 檔案命名 | 類型.名稱.php(如 modifier.truncate_cn.php) |
| 函數命名 | smarty_類型_名稱()(如 smarty_modifier_truncate_cn()) |
| 安裝路徑 | smarty/lib/plugins/ 目錄 |
<?php
/**
* Smarty 中文截取修飾器
* 用法:{$str|truncate_cn:長度:省略字元:起始位置}
*/
function smarty_modifier_truncate_cn($string, $length = 0, $ellipsis = '…', $start = 0) {
// 1. 清理標籤與特殊字元
$string = strip_tags($string);
$string = preg_replace('/\n/is', '', $string);
$string = preg_replace('/ /is', '', $string);
// 2. UTF-8 字元切分(支援多位元組)
preg_match_all(
"/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/",
$string, $matches
);
if (is_array($matches) && !empty($matches[0])) {
$string = implode('', $matches[0]);
if (strlen($string) < $start + 1) return '';
// 3. 精準截取
preg_match_all("/./su", $string, $ar);
$result = '';
$skipped = '';
for ($i = 0; isset($ar[0][$i]); $i++) {
if (strlen($skipped) < $start) {
$skipped .= $ar[0][$i];
} else {
if (strlen($result) < $length + strlen($ar[0][$i])) {
$result .= $ar[0][$i];
} else break;
}
}
return $string === $result ? $result : $result . $ellipsis;
}
return '';
}
?>
modifier.truncate_cn.phpsmarty/lib/plugins/ 目錄{$news.content|truncate_cn:30}| 參數 | 預設值 | 說明 |
|---|---|---|
$length | 0 | 截取長度(字元數,非位元組) |
$ellipsis | … | 超出時的省略字元 |
$start | 0 | 起始位置(跳過前 N 字元) |
若需保留 HTML 結構(如 <b>、<a>),需更複雜的 DOM 解析邏輯,建議使用 HTMLPurifier 或 mb_strimwidth 搭配預處理。