在 PHP 開發中,我們常需要從富文本內容中截取指定長度的摘要。若直接使用 strip_tags 去除標籤,雖然簡單但會導致排版結構盡失,閱讀體驗極差。更棘手的是:若直接按字元截取 HTML 字串,極易切斷標籤導致頁面布局崩潰。本文將介紹兩種成熟的解決方案,幫助你安全截取 HTML 並自動補全閉合標籤。
此方案核心思路是解析 HTML 結構,維護一個標籤堆疊。遇到開始標籤入堆疊,遇到結束標籤出堆疊,文本內容則累計長度。當達到目標長度時停止截取,最後遍歷堆疊補全未閉合標籤。
subHtmlfunction subHtml($html, $length) {
$result = '';
$tagStack = [];
$len = 0;
// 使用正則分割 HTML 標籤與文本,保留分隔符
$contents = preg_split("~(<[^>]+>)~si", $html, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
foreach ($contents as $tag) {
if (trim($tag) === "") continue;
// 自閉合標籤
、
等直接輸出
if (preg_match("~<([a-z0-9]+)[^/>]*/>~si", $tag)) {
$result .= $tag;
}
// 結束標籤 由於中文編碼特性,需配合 mstrlen(計算長度)與 msubstr(截取字串)兩個函數,支援 UTF-8 與 GBK 等編碼,確保中英文混排時長度計算準確。
此方案不依賴正則分割,而是逐字元掃描 HTML 字串,手動解析標籤結構。雖然程式碼較長,但邏輯直觀,適合不想引入正則效能開銷的場景。
phpos_chsubstr_ahtmlfunction phpos_chsubstr_ahtml($str, $num, $more = false) {
$leng = strlen($str);
if ($num >= $leng) return $str;
$word = 0; $i = 0;
$stag = [[]]; $etag = [[]]; // 開始/結束標籤堆疊
$sp = 0; $ep = 0;
while ($word != $num) {
// 處理中文字元(假設 UTF-8 佔 3 位元組)
if (ord($str[$i]) > 128) {
$i += 3; $word++; continue;
}
// 遇到標籤開頭 <
else if ($str[$i] === '<') {
// 解析標籤名稱,分類存入 stag 或 etag
// ...(此處省略詳細解析邏輯,原理同方案一)
$i++; continue;
}
// 普通字元
else { $word++; $i++; }
}
// 匹配開始/結束標籤,過濾掉已閉合與自閉合標籤
// 反轉堆疊並生成補全字串
$ends = '</' . implode('></', array_reverse($stag)) . '>';
$re = substr($str, 0, $i) . $ends;
if ($more) $re .= '...';
return $re;
}
針對部落格、CMS 等場景,利用 mb_ereg 多位元組正則搜尋區塊級標籤(div, p, table 等),建立標籤位置堆疊,精準控制截取邊界,避免破壞佈局結構。
mstrlen/msubstr 計算偏差。<br>、<img> 等無需閉合標籤,邏輯中需顯式排除。HTML 截取的核心難點在於「結構感知」與「多位元組長度計算」。通過維護標籤堆疊實現自動補全,配合 mbstring 擴展處理中文長度,即可構建健壯的摘要生成工具。實際專案中可根據業務複雜度選擇上述方案,並建議封裝為工具類統一維護。