悠悠楠杉
网站页面
正文:
在开发CMS系统、版本控制系统或在线协作平台时,经常需要对比文本内容的差异。本文将手把手教你用PHP实现类似GitDiff的字符串差异高亮功能,让修改内容一目了然。
字符串差异比对的核心是寻找"最长公共子序列"(LCS)。通过将两个字符串分解为字符数组,建立二维矩阵记录匹配状态,最终回溯得到差异路径。PHP中可以通过以下步骤实现:
以下是基于行级对比的基础实现代码:
function highlightDiff($old, $new) {
$oldLines = explode("\n", $old);
$newLines = explode("\n", $new);
$diff = [];
$matrix = [];
$maxLen = 0;
// 构建LCS矩阵
foreach ($oldLines as $i => $oldLine) {
foreach ($newLines as $j => $newLine) {
if ($oldLine === $newLine) {
$matrix[$i][$j] = isset($matrix[$i-1][$j-1])
? $matrix[$i-1][$j-1] + 1
: 1;
if ($matrix[$i][$j] > $maxLen) {
$maxLen = $matrix[$i][$j];
}
} else {
$matrix[$i][$j] = 0;
}
}
}
// 标记差异
$i = count($oldLines) - 1;
$j = count($newLines) - 1;
while ($i >= 0 || $j >= 0) {
if ($i >= 0 && $j >= 0 && $oldLines[$i] === $newLines[$j]) {
$diff[] = "<span class='unchanged'>{$oldLines[$i]}</span>";
$i--; $j--;
} else {
if ($j >= 0 && ($i < 0 || $matrix[$i][$j-1] >= $matrix[$i-1][$j])) {
$diff[] = "<span class='added'>+ {$newLines[$j]}</span>";
$j--;
} elseif ($i >= 0) {
$diff[] = "<span class='removed'>- {$oldLines[$i]}</span>";
$i--;
}
}
}
return implode("\n", array_reverse($diff));
}
当处理大文本时,原始算法可能效率低下。以下是三个优化方向:
优化后的核心逻辑示例:
function optimizedDiff($text1, $text2, $threshold = 0.3) {
$tokens1 = $this->tokenize($text1);
$tokens2 = $this->tokenize($text2);
$similarity = $this->calculateSimilarity($tokens1, $tokens2);
if ($similarity < $threshold) {
return $this->fullDiff($text1, $text2);
}
return $this->lineDiff($text1, $text2);
}
在Wiki系统中应用差异高亮:
配合前端实现的完整方案:
javascript
// 前端渲染差异结果
function renderDiff(diffHtml) {
document.getElementById('diff-container').innerHTML = diffHtml;
$('.added').css('background', '#e6ffe6');
$('.removed').css('background', '#ffe6e6');
}