<?php
/**
* @desc php實現文件對比工具類
*
* @author 劉德生
* @site http://liudsh.duapp.com/
* @since 2016-07-11
*/php
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;"> </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>';
}
}數組