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

PHP 實作 HTML 標籤自動補全閉合(截斷內容不破壞結構)

     編輯:PHP 綜合知識

應用場景

文章摘要、列表頁截取內容時,若直接 substr 截斷 HTML 字串,極易導致標籤未閉合、版面崩壞。本函數可在指定長度截斷時,自動補全未閉合標籤。

核心邏輯

  1. 用正則 ~(<[^>]+?>)~si 將 HTML 拆分為「標籤」與「純文字」片段。
  2. 遍歷片段,維護一個 $tagStack 堆疊:遇到開始標籤 <tag> 入堆,遇到結束標籤 </tag> 匹配出堆,單標籤 <br/> 忽略。
  3. 累計純文字長度(支援中英文混排),達指定長度即停止。
  4. 最後將堆疊剩餘標籤依序補上結束標籤。

完整函數庫

<?php
/**
 * 截取 HTML 並自動補全閉合標籤
 * @param string $html   原始 HTML
 * @param int    $length 最大文字長度(不含標籤)
 * @return string        處理後 HTML
 */
function subHtml($html, $length = 50) {
    $result = '';
    $tagStack = [];
    $len = 0;

    // 分割:保留分隔符(標籤)
    $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 { $result .= msubstr($tag, 0, $length - $len + 1); break; } } } // 補全剩餘未閉合標籤 while (!empty($tagStack)) { $result .= '</' . array_pop($tagStack) . '>'; } return $result; } /** * 多位元組安全截取字串 */ function msubstr($string, $start, $length, $dot = '', $charset = 'UTF-8') { $string = str_replace(['&', '"', '<', '>', ' '], ['&', '"', '<', '>', ' '], $string); if (mb_strlen($string, $charset) <= $length) return $string; if (strtolower($charset) === 'utf-8') { $n = $tn = $noc = 0; while ($n < strlen($string)) { $t = ord($string[$n]); if ($t <= 127) { $tn = 1; $n++; } elseif ($t <= 223) { $tn = 2; $n += 2; } elseif ($t <= 239) { $tn = 3; $n += 3; } elseif ($t <= 247) { $tn = 4; $n += 4; } elseif ($t <= 251) { $tn = 5; $n += 5; } elseif ($t <= 253) { $tn = 6; $n += 6; } else { $n++; } $noc++; if ($noc >= $length) break; } if ($noc > $length) $n -= $tn; $strcut = substr($string, 0, $n); } else { $strcut = ''; for ($i = 0; $i < $length; $i++) { $strcut .= (ord($string[$i]) > 127) ? $string[$i] . $string[++$i] : $string[$i]; } } return $strcut . $dot; } /** * 取得字串長度(中英文皆計 1) */ function mstrlen($str, $charset = 'UTF-8') { if (function_exists('mb_strlen')) return mb_strlen($str, $charset); if (function_exists('iconv_strlen')) return iconv_strlen($str, $charset); 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]/', $str, $ar); return count($ar[0]); } // 測試 $str = "<div><table>x<tr>1s<td>測試<td>124"; echo subHtml($str, 10); // 輸出:
x1s
測試
?>

使用提醒

  • 函數假設 HTML 結構合法,若原始 HTML 本身標籤錯巢,補全結果可能不符預期。
  • 支援 UTF-8 與雙位元組編碼(Big5/GBK),若專案純 UTF-8 可直接用 mb_substr/mb_strlen 簡化。
  • 不處理 <script>/<style> 內容,若需保留請自行擴展。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved