功能特色
- 正確處理巢狀 HTML 標籤,自動補全未閉合標籤
- 中英文均計算為 1 字元長度
- 支援
<!-- break --> 錨點優先截斷
- 超出部分可自訂替換字串(如
...)
核心函數
function cut_html_str(string $str, int $length, string $replace = '', string $anchor = '<!-- break -->'): string {
// 1. 長度檢查
if (mb_strlen($str, 'utf-8') <= $length) return $str;
// 2. 無 HTML 標籤直接截取
if (strpos($str, '<') === false) return mb_substr($str, 0, $length);
// 3. 錨點優先
if (($pos = strpos($str, $anchor)) !== false) {
return mb_substr($str, 0, $pos);
}
// 4. 逐字元解析
$html_tag = 0;
$result = '';
$html_array = ['left' => [], 'right' => []];
$strlen = strlen($str);
for ($i = 0; $i < $strlen && $length > 0; $i++) {
$char = $str[$i];
if ($char === '<') {
$html_tag = 1;
$tag_str = '';
} elseif ($html_tag) {
if ($char === '>') {
$tag_str = trim($tag_str);
// 自閉合標籤略過
if (substr($tag_str, -1) !== '/') {
if ($tag_str[0] === '/') {
$html_array['right'][] = substr($tag_str, 1);
} elseif ($tag_str[0] !== '?') {
// 取標籤名(去除屬性)
$tag_name = strtolower(strpos($tag_str, ' ') ? current(explode(' ', $tag_str, 2)) : $tag_str);
$html_array['left'][] = $tag_name;
}
}
$html_tag = 0;
} else {
$tag_str .= $char;
}
} else {
$length--;
// UTF-8 多位元組處理
$ord = ord($char);
if (($ord & 0xE0) === 0xC0) { $result .= substr($str, $i, 2); $i += 1; }
elseif (($ord & 0xF0) === 0xE0) { $result .= substr($str, $i, 3); $i += 2; }
elseif (($ord & 0xF8) === 0xF0) { $result .= substr($str, $i, 4); $i += 3; }
else { $result .= $char; }
}
}
// 5. 補全未閉合標籤(反向補全)
if ($html_array['left']) {
$html_array['left'] = array_reverse($html_array['left']);
foreach ($html_array['left'] as $tag) {
$key = array_search($tag, $html_array['right']);
if ($key !== false) {
unset($html_array['right'][$key]);
} else {
$result .= "</$tag>";
}
}
}
return $result . $replace;
}
使用範例
$html = '<div><p><b>粗體文字</b>普通文字</p><span>未閉合';
echo cut_html_str($html, 10, '...');
// 輸出: <div><p><b>粗體文</b></p></div>...