首页 > 建站教程 > PHP教程 >  php无损截取包括html标签的字符串正文

php无损截取包括html标签的字符串

在做模板的时候发现问题,首页截取出来的内容中包含了没有闭合的html标签,结果导致样式或内容显示有问题:

假如有一段字符串,例如:
Thanks for use <a href="http://www.wordpress.com><span class="link"></span>wordpress</a>"
如果要截取前面15个字符串,那肯定没问题,如果截取的是20个字符串,那肯定就落在<a>标签里,这么一来截取后再显示取来的内容就有问题,标签不完整,可能会影响样式。
下面的方法可以解决php截取文本时,不会讲html标签截断:
/**
 * 字符串切割
 *
 * 功能:截取字符串(支持中文),如果字符串中包括<a title="查看与html标签有关的文章" href="http://www.5imoban.net" target="_blank">html标签</a>,截取的字符串则会保留完整的<a title="查看与html标签有关的文章" href="http://www.5imoban.net" target="_blank">html标签</a>
 * 如果截取的字符串中包含不完整的html标签,则从字符串位置0开始截取到html标签前
 *
 * @param string $string            
 * @param int $length            
 * @param string $replace            
 * @return string
 */
function htmlSubStr ($string, $length = 0, $replace = '...') {
    // 先截取指定长度的字符串,支持中文
    if (strlen ( $string ) < $length) {
        $string = substr ( $string, 0 );
    } else {
        $char = ord ( $string [$length - 1] );
        if ($char >= 224 && $char <= 239) {
            $string = substr ( $string, 0, $length - 1 );
        } else {
            $char = ord ( $string [$length - 2] );
            if ($char >= 224 && $char <= 239) {
                $string = substr ( $string, 0, $length - 2 );
            } else {
                $string = substr ( $string, 0, $length );
            }
        }
    }

    // 开始标签集合,当前开始标签字符串(a,span,div...),结束标签集合
    $starts = $start_str = $ends = array ();
    // 提取截取的字符串中出现的开始标签结合和结束标签集合
    preg_match_all ( '/<\w+[^>]*>?/', $string, $starts, PREG_OFFSET_CAPTURE );
    preg_match_all ( '/<\/\w+>/', $string, $ends, PREG_OFFSET_CAPTURE );

    // 初始化<a title="查看与字符串截取有关的文章" href="http://cuelog.com/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%88%aa%e5%8f%96" target="_blank">字符串截取</a>点
    $cut_pos = 0;
    // 最后追加的字符串
    $last_str = '';

    if (! empty ( $starts [0] )) {
        $starts = array_reverse ( $starts [0] );
        if (! empty ( $ends [0] )) {
            $ends = $ends [0];
        }

        foreach ( $starts as $sk => $s ) {
            // 判断开始标签是否包括XHTML语法的闭合标签<img alt="">
            $auto = false;
            if ($auto != false && $auto = strripos ( $s [0], "/>' )) {
                // 如果有,则将<a title="查看与字符串截取有关的文章" href="http://cuelog.com/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%88%aa%e5%8f%96" target="_blank">字符串截取</a>点设置为当前标签的起始位置
                if ($cut_pos < $auto) {
                    $cut_pos = $s [1];
                    $last_str = $s [0];
                    unset ( $starts [$sk] );
                }
            } else {
                // 提取开始标签名:a,div,span...
                preg_match ( '/<(\w+).*>?/', $s [0], $start_str );
                if (! empty ( $ends )) {
                    foreach ( $ends as $ek => $e ) {
                        // 提取结束标签名
                        $end_str = trim ( $e [0], '</>' );
                        // 如果开始标签名与结束标签名一致,并且结束标签的索引值比开始标签的索引值大,则该标签是完整的有效.
                        if ($end_str == $start_str [1] && $e [1] > $s [1]) {
                            // 如果字符串截取点还没有确定,给它赋值
                            if ($cut_pos < $e [1]) {
                                $cut_pos = $e [1];
                                // 并且将闭合标签作为最后的字符串追加
                                $last_str = $e [0];
                            }
                            // 将这个正确的标签去掉结束标签,并且滚入下一个开始标签的判断
                            unset ( $ends [$ek] );
                            break;
                        }
                    }
                } else {
                    /*
                     * 如果empty($ends),说明第一个开始标签没有对应的闭合标签 说明这一段截取的内容不完整,只能将字符串截取到第一个开始标签前为止
                     */
                    $last_str = '';
                    $cut_pos = $s [1];
                }
            }
        }
        // 拼凑剩余的字符串
        $res_str = substr ( $string, 0, $cut_pos ) . $last_str;
        $less_str = substr ( $string, strlen ( $res_str ) );
        $less_pos = strpos ( $less_str, '<' );
        $less_str = $less_pos !== false ? substr ( $less_str, 0, $less_pos ) : $less_str;
        $string = $res_str . $less_str . $replace;
    }
    return $string;
}

$str = 'Welcome to hello world,<div class="http://www.baidu.com" class="title">Hey, guys..<b>Hello</b>Look at thie picture<img src="http://www.baidu.com/test.jpg" class="image" /><span><a href="#">Just so so..</a></span></div>Yeah, U R right.<div class="footer">About</div><span>Follow us..<a href="http://www.facebook.com">FB</a></span>';

echo htmlSubStr ( $str, 260 );
// Welcome to hello world,<div class="http://www.baidu.com" class="title">Hey, guys..<b>Hello</b>Look at thie picture<img src="http://www.baidu.com/test.jpg" class="image" /><span><a href="#">Just so so..</a></span></div>Yeah, U R right.<div class="footer">About<