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

PHP 中文混合 HTML 字串截取函式:保留標籤完整性、自動補全未閉合標籤

     編輯:PHP 相關知識

需求:從包含 HTML 標籤的中英混合字串中,按**可見字元長度**截取,標籤不計長度,且輸出結果標籤結構完整(自動補全未閉合標籤)。提供兩種實作。

方法一:狀態機解析(支援標籤堆疊自動補全)

function mysubstr($str, $length) {
    $tagcnt = 0; $charcnt = 0; $tag = '';
    $maxlen = strlen($str);
    $result = '';
    $tagstack = [];

    for ($i = 0; $i < $maxlen && $charcnt < $length; $i++) {
        if ($str[$i] === '<') {
            $result .= $str[$i];
            // 讀取完整標籤
            for ($j = $i; $j < $maxlen && $str[$j] !== '>'; $j++) {
                $tag .= $str[$j];
            }
            $tag .= '>';
            $result .= $tag;
            $i = $j; // 跳過標籤內容
            // 標籤堆疊處理
            if (preg_match('/<([^\/]+?)>/i', $tag, $m)) {
                array_push($tagstack, $m[1]); // 開始標籤入堆疊
            } elseif (preg_match('/<\/'.preg_quote(end($tagstack), '/').'>/i', $tag)) {
                array_pop($tagstack); // 結束標籤出堆疊
            }
            $tag = '';
            continue;
        }
        $charcnt++;
        $result .= $str[$i];
    }

    // 補全未閉合標籤(逆序關閉)
    while (!empty($tagstack)) {
        $t = array_pop($tagstack);
        $result .= "";
    }
    return $result;
}

方法二:正規表達式分割 + 陣列切片(簡潔)

function html_substr($str, $len, $mode = 0) {
    // 分割:保留標籤為獨立元素
    $parts = preg_split('/(|<[^>]*>)/s', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
    foreach ($parts as $k => $v) {
        if ($v[0] !== '<') { // 純文字
            $len -= strlen($v);
            if ($len < 0) {
                $parts[$k] = substr($v, 0, $len + strlen($v)); // 截取文字部分
                $len = 0;
            }
        } else {
            $parts[$k] = strtolower($v); // 標籤轉小寫便於比對
        }
        if ($len <= 0) break;
    }
    $parts = array_slice($parts, 0, $k + 1);

    // 處理未閉合標籤
    if ($mode === 1) { // 模式1:補全
        $openTags = [];
        foreach ($parts as $v) {
            if (preg_match('/<([a-z]+)[^>]*>/i', $v, $m) && !preg_match('/<\//', $v)) {
                $openTags[] = $m[1];
            } elseif (preg_match('/<\/([a-z]+)>/i', $v, $m)) {
                $pos = array_search($m[1], $openTags);
                if ($pos !== false) unset($openTags[$pos]);
            }
        }
        foreach (array_reverse($openTags) as $t) {
            $parts[] = "";
        }
    } else { // 模式0:移除未閉合開始標籤
        // 略
    }
    return join('', $parts);
}

使用範例

$str = "123abc456def789";
echo html_substr($str, 5);       // 123ab (移除未閉合)
echo html_substr($str, 5, 1);    // 123ab (補全)

選擇建議

  • 需精確控制標籤巢狀、自動補全 → 方法一(狀態機)。
  • 簡單截取、效能優先 → 方法二(正規表達式)。
  • 現代專案建議使用成熟庫如 Masterminds/HTML5 或 symfony/string 的 u()->slice()(需 PHP 8.0+)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved