php截取字符串,完美html自动闭合

时间: 2017-02-08  分类: php+Mysql  收藏
在网上查了好多截取的方法,感觉都不是太满意,然后自己想办法整出来了一个,估计有不完美的地方,目前是没发现问题,一个函数, 里面注释比较清楚,测试注释全在,没有删除,现在分享出来,有问题的地址麻烦给提一下,

    //截取字符串, html自动闭合
    public function str_cut_html($string, $length=450) {
        //截取原指定长度
        $substr=mb_substr($string, 0, $length, 'UTF-8');
        //echo $string;die();

        //剩余部分
        $remain=mb_substr($string, $length,mb_strlen($string, 'UTF-8'),'UTF-8');
        //echo $remain;die();

        //剩余小于150 直接使用原string
        if(strlen($remain)<150) return $string;

        //解决前面截取出现断开标签的问题,如<div>被截成<d <等
        $substr_60=mb_substr($substr, -60, 60, 'UTF-8'); //被截取的字符串后60字符
        //echo $substr_60;die();
        $remain_60=mb_substr($remain, 0, 60, 'UTF-8'); //剩余前60字符
        //echo $remain_60;die();
        //剩余前60字符标签数
        preg_match_all('/(<.*?>)/is',$remain_60,$_tags11);
        //print_r($_tages);die();
        $tags11=(isset($_tags11[1]) && $_tags11[1]) ? $_tags11[1] : array();
        $tags11=count($tags11);
        //print_r($tags11);die();
        //被截取的字符串后60字符标签数
        preg_match_all('/(<.*?>)/is',$substr_60,$_tags22);
        //print_r($_tages);die();
        $tags22=(isset($_tags22[1]) && $_tags22[1]) ? $_tags22[1] : array();
        $tags22=count($tags22);
        //print_r($tags22);die();
        //前后120个字符标签数
        preg_match_all('/(<.*?>)/is',$substr_60.$remain_60,$_tags33);
        //print_r($_tages);die();
        $tags33=(isset($_tags33[1]) && $_tags33[1]) ? $_tags33[1] : array();
        $tags33=count($tags33);
        //print_r($tags33);die();

        //存在断开标签
        $bbb='';
        if(($tags11+$tags22)<$tags33) {
            $r=strpos($remain_60, '>'); //第一个标签右>的位置
            $bbb=mb_substr($remain_60, 0, $r+1, 'UTF-8');
            $remain=mb_substr($remain, $r+1);
        }
        //echo $r;die();
        //echo $bbb;die();

        //补全断开标签
        $substr=$substr.$bbb;
        //echo $substr;die();

        //匹配截取内容中所有完整标签
        preg_match_all('/(<.*?>)/is',$substr,$_tages);
        //print_r($_tages);die();
        $tages=(isset($_tages[1]) && $_tages[1]) ? $_tages[1] : array();
        //print_r($tages);die();

        //自闭合标签集特殊处理
        $ignore=array('<br />','<hr />','<br/>','<hr/>', '<img>', '<textarea',
                             '<input>', '<link>', '<source>',
                             '<embed>', '<frame>', '<basefont>','<base>','<col>',
                     );

        //开始结束标签集统计
        $be=$en=array();
        //$_tmp=array();
        foreach($tages as $v) {
            $v=str_replace(array('   ','  '), array(' ',' ') ,strtolower($v));

            //将<img src="" <input=""  <div class="" id="" 等变为<img> <input> <div>
            if(strpos($v, "'") || strpos($v, '"')) {
                $v=substr($v, 0 , strpos($v, ' ')).'>';
            }

            if(in_array($v, $ignore)) continue;

            if(strpos('@@@'.$v, '/')) {
                if(isset($en[$v])) {
                    $en[$v]++;
                } else {
                    $en[$v]=1;
                }
            } else {
                if(isset($be[$v])) {
                    $be[$v]++;
                } else {
                    $be[$v]=1;
                }
            }
            //$_tmp[]=$v;
        }
        //print_r($be);print_r($en);die();

        //需要被闭合的标签位置统计
        $where=array();
        foreach($be as $k=>$c) {
            $k=str_replace('<','</',$k);
            //echo $k;die();
            if(isset($en[$k]) && $c==$en[$k]) continue; //标签闭合无问题
            if(isset($en[$k]) && $c<$en[$k]) continue; //标签多余,属于编辑问题,不处理
            $d=isset($en[$k]) ? $c-$en[$k] : $c; //开始标签比闭合标签多的次数
            //echo $k.$d;die();
            $need[$k]=$d;
            $start=0;
            for($i=1; $i<=$d; $i++) {
                $aa=strpos($remain, $k, $start>0?($start+strlen($k)):$start); //每个未闭合标签位置
                $start=$aa>0?$aa:0;
                $where[$k]=$start+strlen($k);
            }
        }
        //print_r($where);die();
        sort($where);
        //print_r($where);die();
        $last=array_pop($where);
        //echo $last;die();

        //截取后面被闭合标签及前面内容
        $need=substr($remain, 0, $last);
        //echo $need;die();

        $substr.=$need;
        return $substr;
    }

分享到:

评论

昵 称: