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

PHP 截取 HTML 字串並自動補全標籤的完整解決方案

     編輯:PHP 綜合知識

前言

在 PHP 開發中,我們常需要從富文本內容中截取指定長度的摘要。若直接使用 strip_tags 去除標籤,雖然簡單但會導致排版結構盡失,閱讀體驗極差。更棘手的是:若直接按字元截取 HTML 字串,極易切斷標籤導致頁面布局崩潰。本文將介紹兩種成熟的解決方案,幫助你安全截取 HTML 並自動補全閉合標籤。

方案一:基於堆疊機制的精準截取

此方案核心思路是解析 HTML 結構,維護一個標籤堆疊。遇到開始標籤入堆疊,遇到結束標籤出堆疊,文本內容則累計長度。當達到目標長度時停止截取,最後遍歷堆疊補全未閉合標籤。

核心函數 subHtml

function 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; } // 結束標籤
等,匹配堆疊頂部則出堆疊 elseif (preg_match("~</([a-z0-9]+)[^/>]*>~si", $tag, $match)) { if (!empty($tagStack) && $tagStack[count($tagStack)-1] === $match[1]) { array_pop($tagStack); $result .= $tag; } } // 開始標籤
等,推入堆疊 elseif (preg_match("~<([a-z0-9]+)[^/>]*>~si", $tag, $match)) { array_push($tagStack, $match[1]); $result .= $tag; } // 註釋標籤直接輸出 elseif (preg_match("~<!--.*-->~si", $tag)) { $result .= $tag; } // 純文本內容,計算長度並截取 else { if ($len + mstrlen($tag) < $length) { $result .= $tag; $len += mstrlen($tag); } else { $str = msubstr($tag, 0, $length - $len + 1); $result .= $str; break; } } } // 補全剩餘未閉合標籤 while (!empty($tagStack)) { $result .= '</' . array_pop($tagStack) . '>'; } return $result; }

輔助函數:多位元組字串處理

由於中文編碼特性,需配合 mstrlen(計算長度)與 msubstr(截取字串)兩個函數,支援 UTF-8 與 GBK 等編碼,確保中英文混排時長度計算準確。

方案二:字元級遍歷的輕量級實現

此方案不依賴正則分割,而是逐字元掃描 HTML 字串,手動解析標籤結構。雖然程式碼較長,但邏輯直觀,適合不想引入正則效能開銷的場景。

核心函數 phpos_chsubstr_ahtml

function 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 等),建立標籤位置堆疊,精準控制截取邊界,避免破壞佈局結構。

最佳實踐建議

  • 優先使用方案一:正則分割+堆疊機制,代碼結構清晰,易於維護擴展。
  • 編碼統一:確保專案編碼一致(建議 UTF-8),避免 mstrlen/msubstr 計算偏差。
  • 效能考量:超長 HTML 內容建議先提取純文本摘要,或使用緩存機制減少重複解析。
  • 特殊標籤處理:<br>、<img> 等無需閉合標籤,邏輯中需顯式排除。

總結

HTML 截取的核心難點在於「結構感知」與「多位元組長度計算」。通過維護標籤堆疊實現自動補全,配合 mbstring 擴展處理中文長度,即可構建健壯的摘要生成工具。實際專案中可根據業務複雜度選擇上述方案,並建議封裝為工具類統一維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved