截取文本但不截断HTML代码

4

这个字符串包含78个HTML字符和39个非HTML字符:

<p>I really like the <a href="http://google.com">Google</a> search engine.</p>

我希望根据非HTML字符计数截断此字符串,例如,如果我想将上面的字符串截断为24个字符,则输出结果为:
I really like the <a href="http://google.com">Google</a>

截断时只考虑了剥离后的字符数量,而未考虑 HTML 标签,因此截断没有保留未闭合的 HTML 标签。

1
我建议你研究一下XML解析器;它们很可能是确保你不会破坏HTML/知道什么是或不是显示文本的唯一方法。 - KRyan
1个回答

9

好的,这是我整理出来的,看起来它正在工作:

function truncate_html($string, $length, $postfix = '&hellip;', $isHtml = true) {
    $string = trim($string);
    $postfix = (strlen(strip_tags($string)) > $length) ? $postfix : '';
    $i = 0;
    $tags = []; // change to array() if php version < 5.4

    if($isHtml) {
        preg_match_all('/<[^>]+>([^<]*)/', $string, $tagMatches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
        foreach($tagMatches as $tagMatch) {
            if ($tagMatch[0][1] - $i >= $length) {
                break;
            }

            $tag = substr(strtok($tagMatch[0][0], " \t\n\r\0\x0B>"), 1);
            if ($tag[0] != '/') {
                $tags[] = $tag;
            }
            elseif (end($tags) == substr($tag, 1)) {
                array_pop($tags);
            }

            $i += $tagMatch[1][1] - $tagMatch[0][1];
        }
    }

    return substr($string, 0, $length = min(strlen($string), $length + $i)) . (count($tags = array_reverse($tags)) ? '</' . implode('></', $tags) . '>' : '') . $postfix;
}

使用方法:

truncate_html('<p>I really like the <a href="http://google.com">Google</a> search engine.</p>', 24);

该函数被提取自(进行了小修改):

http://www.dzone.com/snippets/truncate-text-preserving-html


1
单字母变量和没有解释参数是不够的。希望在这里看到一些解释,因为这个函数似乎非常好而且简洁。 - Greg
这将在最后一个闭合标签之后添加“后缀”。在某些情况下可能是有益的,但在我的情况下,它会导致“…”单独出现在最后一行。不太美观。 - Ariane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接