首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 截取 HTML 字串並保持標籤完整性:Tidy + DOM 方案

     編輯:PHP 綜合知識

問題情境

需從 HTML 片段中截取前 N 個字元 (含中文),且**不能破壞標籤結構** (如 `` 未閉合)。直接字串截斷會導致標籤殘缺,前端渲染錯誤。

解決方案:Tidy 修正 → DOM 遍歷文字節點 → 重新組裝

Step 1:Tidy 將片段補全為合法文件

$tidy = tidy_parse_string($htmlFragment, [
    'output-xhtml' => true,
    'show-body-only' => true,
    'wrap' => 0
], 'utf8'); // 注意:'utf8' 非 'utf-8'

$body = tidy_get_body($tidy); // 取得  節點物件

Step 2:遞迴遍歷文字節點並累計寬度

function truncateHtml($node, &$len, &$output) {
    if ($node->type === TIDY_NODETEXT) {
        $text = $node->value;
        $width = mb_strwidth($text, 'utf-8'); // 中文算 2 寬度
        if ($width <= $len) {
            $output .= $text;
            $len -= $width;
        } else {
            $output .= mb_strimwidth($text, 0, $len, '…', 'utf-8');
            $len = 0;
            return false; // 停止遍歷
        }
    } elseif ($node->type === TIDY_NODestart || $node->type === TIDY_NODEEND) {
        // 標籤節點:直接輸出原始標籤
        $output .= $node->value;
    }

    // 遞迴子節點
    if (isset($node->child)) {
        foreach ($node->child as $child) {
            if (!$len) break;
            if (!truncateHtml($child, $len, $output)) break;
        }
    }
    return true;
}

// 使用
$maxWidth = 100; // 目標寬度 (中文 50 字)
$output = '';
truncateHtml($body, $maxWidth, $output);
echo $output; // 完整標籤 + 截斷後文字

關鍵函數

  • mb_strwidth():依字元寬度計算長度 (中文=2, 英文=1),完美符合排版需求。
  • mb_strimwidth():同樣依寬度截斷並可加省略號。

替代方案比較

方案優點缺點
Tidy + DOM (本文)標籤 100% 完整、支援巢狀、寬度精確需安裝 tidy 擴展、效能稍低
正則 + 狀態機無擴展相依極難處理巢狀/屬性含 `>`/CDATA/註解等邊界情況
前端 CSS text-overflow:ellipsis零後端成本、效能最好Firefox 早期不支援、多行截斷需 `-webkit-line-clamp`、SEO 看不到完整內容

生產環境建議

  1. 將上述邏輯封裝為 function html_truncate($html, $maxWidth, $ellipsis = '…')。
  2. 快取 Tidy 解析結果 (若同內容重複使用)。
  3. 若 HTML 來源可信且結構固定,考慮直接在資料層截斷純文字再套版,效能最佳。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved