Выделите разницу между двумя строками в PHP

Каков самый простой способ подчеркнуть разницу между двумя строками в PHP?

Я думаю по строкам истории истории переполнения стека, где новый текст находится в зеленом, а удаленный текст – красным. Если есть какие-либо заранее написанные функции или классы, это было бы идеально.

Solutions Collecting From Web of "Выделите разницу между двумя строками в PHP"

Вы можете использовать пакет PHP Horde_Text_Diff . Это соответствует вашим потребностям и вполне настраивается.

Он также лицензирован под GPL, так что наслаждайтесь!

Просто написал класс, чтобы вычислить наименьшее (не считаться буквально) количество редактирований, чтобы преобразовать одну строку в другую строку:

http://www.raymondhill.net/finediff/

Он имеет статическую функцию для рендеринга HTML-версии diff.

Это первая версия и, вероятно, она будет улучшена, но на данный момент она работает отлично, поэтому я выбрасываю ее там, где кому-то нужно создать компактный diff, как мне было нужно.

Изменить: Сейчас на Github: https://github.com/gorhill/PHP-FineDiff

Если вам нужна надежная библиотека, Text_Diff (пакет PEAR) выглядит довольно неплохо. У этого есть некоторые довольно интересные особенности.

Это неплохо, также http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/

Решение проблемы не так просто, как кажется, и проблема беспокоила меня примерно за год до того, как я понял это. Мне удалось написать свой алгоритм в PHP, в 18 строках кода. Это не самый эффективный способ сделать diff, но, вероятно, это проще всего понять.

Он работает путем нахождения самой длинной последовательности слов, общих для обеих строк, и рекурсивного поиска самых длинных последовательностей остатков строки до тех пор, пока подстроки не будут иметь общих слов. В этот момент он добавляет оставшиеся новые слова в качестве вставки, а оставшиеся старые слова – как удаление.

Вы можете скачать исходный код здесь: PHP SimpleDiff …

Существует также расширение PECL для xdiff:

В частности:

  • xdiff_string_diff – Сделать унифицированный diff двух строк

Пример из руководства 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; } 

Вот краткая функция, которую вы можете использовать для разграничения двух массивов. Он реализует алгоритм 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); } 

Он генерирует два массива:

  • values ​​array: список элементов, как они появляются в diff.
  • Маска: содержит числа. 0: без изменений, -1: удалено, 1: добавлено.

Если вы заполняете массив символами, его можно использовать для вычисления inline-разницы. Теперь просто один шаг, чтобы подчеркнуть различия:

 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; } 

Например.:

 echo diffline('StackOverflow', 'ServerFault') 

Вывод:

 S<del>tackO</del><ins>er</ins>ver<del>f</del><ins>Fau</ins>l<del>ow</del><ins>t</ins> 

S Tacko ервере е Фол вл T

Дополнительные замечания:

  • Для матрицы дифракции требуются элементы (m + 1) * (n + 1). Таким образом, вы можете столкнуться с ошибками памяти, если попытаетесь использовать длинные последовательности. В этом случае сначала разберите более крупные куски (например, линии), а затем разделите их содержимое на второй проход.
  • Алгоритм может быть улучшен, если вы обрезаете совпадающие элементы с начала и конца, а затем запустите алгоритм только на различной середине. В последней (более раздутой) версии также содержатся эти модификации.

Это лучшее, что я нашел.

http://code.stephenmorley.org/php/diff-implementation/

введите описание изображения здесь

То, что вы ищете, – это «алгоритм сравнения». Быстрый поиск в Google привел меня к этому решению . Я не тестировал его, но, возможно, он будет делать то, что вам нужно.

У меня были ужасные проблемы с обеими 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); } } 

Порт php для Neil Frasers diff_match_patch (лицензия на Apache 2.0)

Я бы рекомендовал посмотреть на эти потрясающие функции из ядра PHP:

Similar_text – Рассчитать сходство между двумя строками

http://www.php.net/manual/en/function.similar-text.php

levenshtein – Рассчитать расстояние Левенштейна между двумя строками

http://www.php.net/manual/en/function.levenshtein.php

soundex – Вычислить звуковой ключ строки

http://www.php.net/manual/en/function.soundex.php

metaphone – Вычислить ключ метафона строки

http://www.php.net/manual/en/function.metaphone.php

Я наткнулся на этот класс PHP diff Крисом Бултоном на основе Python difflib, который может быть хорошим решением:

PHP Diff Lib