文档章节

php实现文件内容对比并加亮显示工具类

刘德生
 刘德生
发布于 2016/07/11 19:42
字数 751
阅读 52
收藏 3

<?php
/**
* @desc  php实现文件对比工具类
*
* @author  刘德生
* @site  http://liudsh.duapp.com/
* @since 2016-07-11
*/

class fileDiff {
    /**
     * 获取文件
     *
     * @param array $arrParam
     * @return array
     */
    public function diff($strContent1, $strContent2) {
        //按行拆分文件
        $arrContentLine1 = explode(PHP_EOL, $strContent1);
        $arrContentLine2 = explode(PHP_EOL, $strContent2);
        $intN1 = count($arrContentLine1);
        $intN2 = count($arrContentLine2);
        $strAjustLine = '<span style="background:#0b0;">&nbsp;&nbsp;</span><br/>';
        if (!$strContent1) {
            $strRet2 = $this->_setDiffColor($strContent2);
            $strRet2 = str_replace(PHP_EOL, '<br/>', $strRet2);
            $strRet1 = str_repeat($strAjustLine, $intN2);
        } else if (!$strContent2) {
            $strRet1 = $this->_setDiffColor($strContent1);
            $strRet1 = str_replace(PHP_EOL, '<br/>', $strRet1);
            $strRet2 = str_repeat($strAjustLine, $intN1);
        } else {
            $strRet1 = $strRet2 = ''; //对比结果    
            for($i=0,$j=0; $i < $intN1 && $j < $intN2; ++$i,++$j) {
                if (empty($arrContentLine1[$i]) && $arrContentLine2[$j]) {
                    $strRet1 .= '<br/>';
                    $strRet2 .= $strAjustLine;
                    --$j;
                    continue;
                }
                if (empty($arrContentLine2[$j]) && $arrContentLine1[$i]) {
                    $strRet1 .= $strAjustLine;
                    $strRet2 .= '<br/>';
                    --$i;
                    continue;
                }
                
                $arrCmp = $this->_diffLine($arrContentLine1[$i], $arrContentLine2[$j]);
                if ($arrCmp['is_same'] != 1) {//不相同
                    //剩余行数
                    $intL1 = $intN1 - $i - 1; 
                    $intL2 = $intN2 - $j - 1;
                    if ($intL1 > $intL2) {
                        $intDiff = $intL1 - $intL2;
                        $intSkip = 0; //大于0表示数组1迁移几行有相同
                        $arrDiffTmp = array();
                        $strSameTmp = '';
                        for($k=1; $k<=$intDiff; ++$k) {
                            $arrTmp = $this->_diffLine($arrContentLine1[$i+$k], $arrContentLine2[$j]);
                            if ($arrTmp['is_same'] == 1) { //相同
                                $intSkip = $k;
                                $strSameTmp = $arrContentLine2[$j];
                                break;
                            } else {
                                $arrDiffTmp[] = $arrContentLine1[$i+$k];
                            }
                        }
                        if ($intSkip > 0 || $intL2 == 0) {
                            $strRet1 .= $this->_setDiffColor($arrContentLine1[$i]) . '<br/>'; 
                            $strRet2 .= $strAjustLine;
                            $i += $intSkip;
                            if ($arrDiffTmp) {
                                foreach ($arrDiffTmp as $str) {
                                    $strRet1 .= $this->_setDiffColor($str). '<br/>';
                                    $strRet2 .= $strAjustLine;
                                }
                            }
                            $strRet1 .= $strSameTmp. '<br/>';
                            $strRet2 .= $strSameTmp. '<br/>';
                        } else {
                            $strRet1 .= $arrCmp['str1'] . '<br/>';
                            $strRet2 .= $arrCmp['str2'] . '<br/>'; 
                        }
                    } else if ($intL1 < $intL2) {
                        $intDiff = $intL2 - $intL1;
                        $intSkip = 0; //大于0表示数组1迁移几行有相同
                        $arrDiffTmp = array();
                        $strSameTmp = '';
                        for($k=1; $k<=$intDiff; ++$k) {
                            $arrTmp = $this->_diffLine($arrContentLine1[$i], $arrContentLine2[$j+$k]);
                            if ($arrTmp['is_same'] == 1) { //相同
                                $intSkip = $k;
                                $strSameTmp = $arrContentLine1[$i];
                                break;
                            } else {
                                $arrDiffTmp[] = $arrContentLine2[$j+$k];
                            }
                        }
                        
                        if ($intSkip > 0 || $intL1 == 0) {
                            $strRet1 .= $strAjustLine;
                            $strRet2 .= $this->_setDiffColor($arrContentLine2[$j]) . '<br/>'; 
                            $j += $intSkip;
                            if ($arrDiffTmp) {
                                foreach ($arrDiffTmp as $str) {
                                    $strRet1 .= $strAjustLine;
                                    $strRet2 .= $this->_setDiffColor($str). '<br/>';
                                }
                            }
                            $strRet1 .= $strSameTmp. '<br/>';
                            $strRet2 .= $strSameTmp. '<br/>';
                        } else {
                            $strRet1 .= $arrCmp['str1'] . '<br/>';
                            $strRet2 .= $arrCmp['str2'] . '<br/>'; 
                        }
                    } else {
                        $strRet1 .= $arrCmp['str1'] . '<br/>';
                        $strRet2 .= $arrCmp['str2'] . '<br/>';
                    }
                } else {
                    $strRet1 .= $arrCmp['str1'] . '<br/>';
                    $strRet2 .= $arrCmp['str2'] . '<br/>';
                }
            }
        }
        
        $arrRet = array(
            'content1' => $strRet1,
            'content2' => $strRet2,
        );
        
        return $arrRet;
    }
    
    /**
     * 按行对比
     *
     * @param string $str1
     * @param string $str2
     * @return array
     */
    private function _diffLine($str1, $str2) {
        $strSplit = "/[\s,.!?:;。,!?;]+/u";
        $arrWord1 = preg_split($strSplit, $str1, -1, PREG_SPLIT_OFFSET_CAPTURE);
        $arrWord2 = preg_split($strSplit, $str2, -1, PREG_SPLIT_OFFSET_CAPTURE);
        $intN1 = count($arrWord1);
        $intN2 = count($arrWord2);
        $arrFlag1 = $arrFlag2 = array();//标记相同部分
        for($i=0,$j=0; $i < $intN1 && $j < $intN2; ++$i,++$j) {
            if ($arrWord1[$i][0] != $arrWord2[$j][0]) {
                //剩余部分份数
                $intL1 = $intN1 - $i - 1; 
                $intL2 = $intN2 - $j - 1;
                if ($intL1 > $intL2) {
                    $intDiff = $intL1 - $intL2;
                    $intSkip = 0; //大于0表示数组1迁移几位有相同
                    for($k=1; $k<=$intDiff; ++$k) {
                        if ($arrWord1[$i+$k][0] == $arrWord2[$j][0]) { //相同
                            $intSkip = $k;
                            break;
                        }
                    }
                    if ($intSkip > 0) {
                        $i += $intSkip;
                        $arrFlag1[$i] = 1;
                        $arrFlag2[$j] = 1;
                    } 
                } else if ($intL1 < $intL2) {
                    $intDiff = $intL2 - $intL1;
                    $intSkip = 0; //大于0表示数组1迁移几位有相同
                    for($k=1; $k<=$intDiff; ++$k) {
                        if ($arrWord2[$j+$k][0] == $arrWord1[$i][0]) { //相同
                            $intSkip = $k;
                            break;
                        }
                    }
                    if ($intSkip > 0) {
                        $j += $intSkip;
                        $arrFlag1[$i] = 1;
                        $arrFlag2[$j] = 1;
                    } 
                } 
            }else {
                $arrFlag1[$i] = 1;
                $arrFlag2[$j] = 1;
            }
        }
        
        $strRet = '';
        $pos = 0;
        for($k=0; $k < $intN1; ++$k) {
            if ($k > 0) {
                $strRet .= substr($str1, $pos, $arrWord1[$k][1]-$pos);
            } 
            if ($arrFlag1[$k]) {
                $strRet .= $arrWord1[$k][0];
            } else {
                $strRet .= $this->_setDiffColor($arrWord1[$k][0]);
            }
            $pos = $arrWord1[$k][1] + strlen($arrWord1[$k][0]);
        }
        $arrRet = array();
        $arrRet['str1'] = $strRet;
        $strRet = '';
        $pos = 0;
        for($k=0; $k < $intN2; ++$k) {
            if ($k > 0) {
                $strRet .= substr($str2, $pos, $arrWord2[$k][1]-$pos);
            }
            if ($arrFlag2[$k]) {
                $strRet .= $arrWord2[$k][0];
            } else {
                $strRet .= $this->_setDiffColor($arrWord2[$k][0]);
            }
            $pos = $arrWord2[$k][1] + strlen($arrWord2[$k][0]);
        }
        $arrRet['str2'] = $strRet;
        $arrRet['is_same'] = ($intN1 == $intN2 && count($arrFlag1) == $intN1 && count($arrFlag2) == $intN2)?1:0;
        return $arrRet;
    }
    
    /**
     * 设置不同文字颜色
     *
     * @param string $str
     * @return string
     */
    private function _setDiffColor($str) {
        return '<span style="color:#ff5809">' . $str . '</span>';
    }
}

© 著作权归作者所有

共有 人打赏支持
刘德生
粉丝 6
博文 31
码字总数 7734
作品 0
海淀
高级程序员
私信 提问
加载中

评论(1)

C/C++集成开发环境--C-Free

C-Free是一款支持多种编译器的专业化C/C++集成开发环境(IDE)。利用本软件,使用者可以轻松地编辑、编译、连接、运行、调试C/C++程序。 C-Free 5 主要有以下特性: 1. 支持多编译器,可以配...

匿名
2012/09/19
11.5K
0
PHP语法加亮类--KindSyntax

KindSyntax是用PHP做的程序语法加亮类,支持HTML、 JavaScript、 PHP、 Perl等语言的高亮显示,可以替代PHP自带的highlight函数。 使用方法请参考压缩包里的README.txt文件。 在线演示:htt...

匿名
2008/11/30
1K
0
C-Free汉化版

名称:C-Free汉化版版本:1.0软件大小:14.1MB软件语言:简体中文软件授权:免费版应用平台:Win7/Vista/Win2003/WinXPC-Free是一款支持多种编译器的专业化C/C++集成开发环境(IDE)。利用C...

相心的泪
2016/08/01
56
0
FineReader如何不通过识别快速创建电子档案

很多用户每天都要处理大量传入的文档,比如,律师要处理案例和客户的成千上万个文档页面,这些案例文档经常几乎同时出现,要么就是接踵而至,文档附件需快速制作,工作才能得以开始。怎样才能...

ABBYY
2015/12/09
24
0
PHP代码加亮工具——GeSHi 的安装和使用

代码加亮工具GeSHi的安装轻而易举,即便对PHP新手也一样,不需要什么技巧^_^ GeSHi需要如下环境: PHP 4.1.0以上 作者在 4.3.X 环境下进行了测试。同时,大量的应用表明GeSHi的稳定性很好,适...

红薯
2010/09/16
1K
3

没有更多内容

加载失败,请刷新页面

加载更多

方之熙博士被任命为RISC-V基金会中国顾问委员会主席,加速RISC-V ISA在中国的应用

中国顾问委员会将就RISC-V基金会的教育和应用推广战略提供指导 今天在中国乌镇举行的世界互联网大会(World Internet Conference)上,RISC-V基金会(RISC-V Foundation)宣布,半导体行业资深人...

whoisliang
21分钟前
0
0
为了用户体验,不要做浏览器兼容

读者看到文章标题也许会感到奇怪,按照通常的经验来说,为了用户体验应该做浏览器兼容,以便让不同的浏览器用户都能有好的体验,从而增加网站的流量,但是我认为做浏览器兼容属于同样的工作重...

Bob2100
21分钟前
0
0
分布式定时任务架构 (二) xxl-job二次开发实践

4个月前,公司有任务调度的需求,需要一周内完成,时间非常紧。 需求有三点: web界面编辑cron表达式,启动,停止任务 接入公司的rpc成本较低,公司有自研的rpc,研发人员希望共用同一套注解 ...

勇哥和你一起学技术
38分钟前
0
0
React和Redux的连接react-redux

通过Redux文档来了解react-redux,在一段时间的实践后准备翻一翻源代码,顺便做些相关的总结。我看的代码的npm版本为v4.0.0,也就是说使用的React版本是0.14.x。 react-redux提供两个关键模块...

前端攻城老湿
59分钟前
1
0
1、Mybatis连接池配置 和 Context.xml的配置

注意: (1)mybatis 3.2 之前 通过 set get 方法 获取相关属性。之后通过属性姓名获取相关关联。 (2)mybatis 映射 优先为 sql 语句中的别名与实体类的属性进行映射。 (3)jndi Java用于调...

KingFightingAn
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部