突出显示 PHP 中两个字符串的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/321294/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Highlight the difference between two strings in PHP
提问by Philip Morton
What is the easiest way to highlight the difference between two strings in PHP?
在 PHP 中突出显示两个字符串之间差异的最简单方法是什么?
I'm thinking along the lines of the Stack Overflow edit history page, where new text is in green and removed text is in red. If there are any pre-written functions or classes available, that would be ideal.
我正在考虑 Stack Overflow 编辑历史记录页面的内容,其中新文本为绿色,删除的文本为红色。如果有任何可用的预先编写的函数或类,那将是理想的。
采纳答案by M.N
You can use the PHP Horde_Text_Diffpackage. It suits your needs, and is quite customisable as well.
您可以使用PHP Horde_Text_Diff包。它适合您的需求,并且也非常可定制。
It's also licensed under the GPL, so Enjoy!
它也在 GPL 下获得许可,所以享受吧!
回答by R. Hill
Just wrote a class to compute smallest (not to be taken literally) number of edits to transform one string into another string:
刚刚编写了一个类来计算将一个字符串转换为另一个字符串的最小(不是字面意思)编辑次数:
http://www.raymondhill.net/finediff/
http://www.raymondhill.net/finediff/
It has a static function to render a HTML version of the diff.
它有一个静态函数来呈现差异的 HTML 版本。
It's a first version, and likely to be improved, but it works just fine as of now, so I am throwing it out there in case someone needs to generate a compact diff efficiently, like I needed.
这是第一个版本,可能会得到改进,但到目前为止它工作得很好,所以我把它扔在那里,以防有人需要有效地生成一个紧凑的差异,就像我需要的那样。
Edit: It's on Github now: https://github.com/gorhill/PHP-FineDiff
编辑:现在在 Github 上:https: //github.com/gorhill/PHP-FineDiff
回答by Softy
This is a nice one, also http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/
这是一个很好的,也是 http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/
Solving the problem is not as simple as it seems, and the problem bothered me for about a year before I figured it out. I managed to write my algorithm in PHP, in 18 lines of code. It is not the most efficient way to do a diff, but it is probably the easiest to understand.
It works by finding the longest sequence of words common to both strings, and recursively finding the longest sequences of the remainders of the string until the substrings have no words in common. At this point it adds the remaining new words as an insertion and the remaining old words as a deletion.
You can download the source here: PHP SimpleDiff...
问题的解决并不像看起来那么简单,这个问题困扰了我大约一年才弄明白。我设法用 18 行代码用 PHP 编写了我的算法。这不是进行差异的最有效方法,但它可能是最容易理解的。
它的工作原理是找到两个字符串共有的最长单词序列,然后递归地查找字符串剩余部分的最长序列,直到子字符串没有共同的单词为止。此时,它将剩余的新词添加为插入,将剩余的旧词添加为删除。
你可以在这里下载源代码:PHP SimpleDiff...
回答by Wickethewok
回答by Calmarius
Here is a short function you can use to diff two arrays. It implements the LCSalgorithm:
这是一个可用于比较两个数组的简短函数。它实现了LCS算法:
function computeDiff($from, $to)
{
$diffValues = array();
$diffMask = array();
$dm = array();
$n1 = count($from);
$n2 = count($to);
for ($j = -1; $j < $n2; $j++) $dm[-1][$j] = 0;
for ($i = -1; $i < $n1; $i++) $dm[$i][-1] = 0;
for ($i = 0; $i < $n1; $i++)
{
for ($j = 0; $j < $n2; $j++)
{
if ($from[$i] == $to[$j])
{
$ad = $dm[$i - 1][$j - 1];
$dm[$i][$j] = $ad + 1;
}
else
{
$a1 = $dm[$i - 1][$j];
$a2 = $dm[$i][$j - 1];
$dm[$i][$j] = max($a1, $a2);
}
}
}
$i = $n1 - 1;
$j = $n2 - 1;
while (($i > -1) || ($j > -1))
{
if ($j > -1)
{
if ($dm[$i][$j - 1] == $dm[$i][$j])
{
$diffValues[] = $to[$j];
$diffMask[] = 1;
$j--;
continue;
}
}
if ($i > -1)
{
if ($dm[$i - 1][$j] == $dm[$i][$j])
{
$diffValues[] = $from[$i];
$diffMask[] = -1;
$i--;
continue;
}
}
{
$diffValues[] = $from[$i];
$diffMask[] = 0;
$i--;
$j--;
}
}
$diffValues = array_reverse($diffValues);
$diffMask = array_reverse($diffMask);
return array('values' => $diffValues, 'mask' => $diffMask);
}
It generates two arrays:
它生成两个数组:
- values array: a list of elements as they appear in the diff.
- mask array: contains numbers. 0: unchanged, -1: removed, 1: added.
- values 数组:出现在差异中的元素列表。
- 掩码数组:包含数字。0:不变,-1:删除,1:添加。
If you populate an array with characters, it can be used to compute inline difference. Now just a single step to highlight the differences:
如果使用字符填充数组,则可以使用它来计算内联差异。现在只需一步即可突出差异:
function diffline($line1, $line2)
{
$diff = computeDiff(str_split($line1), str_split($line2));
$diffval = $diff['values'];
$diffmask = $diff['mask'];
$n = count($diffval);
$pmc = 0;
$result = '';
for ($i = 0; $i < $n; $i++)
{
$mc = $diffmask[$i];
if ($mc != $pmc)
{
switch ($pmc)
{
case -1: $result .= '</del>'; break;
case 1: $result .= '</ins>'; break;
}
switch ($mc)
{
case -1: $result .= '<del>'; break;
case 1: $result .= '<ins>'; break;
}
}
$result .= $diffval[$i];
$pmc = $mc;
}
switch ($pmc)
{
case -1: $result .= '</del>'; break;
case 1: $result .= '</ins>'; break;
}
return $result;
}
Eg.:
例如。:
echo diffline('StackOverflow', 'ServerFault')
Will output:
将输出:
S<del>tackO</del><ins>er</ins>ver<del>f</del><ins>Fau</ins>l<del>ow</del><ins>t</ins>
StackOerverfFaulowt
秒粘性永远F故障哦吨
Additional notes:
补充说明:
- The diff matrix requires (m+1)*(n+1) elements. So you can run into out of memory errors if you try to diff long sequences. In this case diff larger chunks (eg. lines) first, then diff their contents in a second pass.
- The algorithm can be improved if you trim the matching elements from the beginning and the end, then run the algorithm on the differing middle only. A latter (more bloated) versioncontains these modifications too.
- diff 矩阵需要 (m+1)*(n+1) 个元素。因此,如果您尝试区分长序列,可能会遇到内存不足错误。在这种情况下,首先比较较大的块(例如行),然后在第二遍中比较它们的内容。
- 如果从开头和结尾修剪匹配元素,然后仅在不同的中间运行算法,则可以改进算法。一个后(更臃肿)版本包含这些修改过。
回答by Gordon
There is also a PECL extension for xdiff:
xdiff 还有一个 PECL 扩展:
In particular:
特别是:
- xdiff_string_diff— Make unified diff of two strings
- xdiff_string_diff— 两个字符串的统一差异
Example from PHP Manual:
PHP 手册中的示例:
<?php
$old_article = file_get_contents('./old_article.txt');
$new_article = $_POST['article'];
$diff = xdiff_string_diff($old_article, $new_article, 1);
if (is_string($diff)) {
echo "Differences between two articles:\n";
echo $diff;
}
回答by xgretsch
I had terrible trouble with the both the PEAR-based and the simpler alternatives shown. So here's a solution that leverages the Unix diff command (obviously, you have to be on a Unix system or have a working Windows diff command for it to work). Choose your favourite temporary directory, and change the exceptions to return codes if you prefer.
我在显示基于 PEAR 的和更简单的替代方案时遇到了可怕的麻烦。所以这里有一个利用 Unix diff 命令的解决方案(显然,你必须在 Unix 系统上或有一个有效的 Windows diff 命令才能工作)。选择您最喜欢的临时目录,并根据需要更改异常以返回代码。
/**
* @brief Find the difference between two strings, lines assumed to be separated by "\n|
* @param $new string The new string
* @param $old string The old string
* @return string Human-readable output as produced by the Unix diff command,
* or "No changes" if the strings are the same.
* @throws Exception
*/
public static function diff($new, $old) {
$tempdir = '/var/somewhere/tmp'; // Your favourite temporary directory
$oldfile = tempnam($tempdir,'OLD');
$newfile = tempnam($tempdir,'NEW');
if (!@file_put_contents($oldfile,$old)) {
throw new Exception('diff failed to write temporary file: ' .
print_r(error_get_last(),true));
}
if (!@file_put_contents($newfile,$new)) {
throw new Exception('diff failed to write temporary file: ' .
print_r(error_get_last(),true));
}
$answer = array();
$cmd = "diff $newfile $oldfile";
exec($cmd, $answer, $retcode);
unlink($newfile);
unlink($oldfile);
if ($retcode != 1) {
throw new Exception('diff failed with return code ' . $retcode);
}
if (empty($answer)) {
return 'No changes';
} else {
return implode("\n", $answer);
}
}
回答by Andy
This is the best one I've found.
这是我找到的最好的一个。
http://code.stephenmorley.org/php/diff-implementation/
http://code.stephenmorley.org/php/diff-implementation/


回答by Peter Bailey
What you are looking for is a "diff algorithm". A quick google search led me to this solution. I did not test it, but maybe it will do what you need.
您正在寻找的是“差异算法”。一个快速的谷歌搜索让我找到了这个解决方案。我没有测试它,但也许它会做你需要的。
回答by hakre
A php port of Neil Frasers diff_match_patch(Apache 2.0 licensed)
Neil Frasers diff_match_patch 的 php 端口(Apache 2.0 许可)

