web-dev-qa-db-ja.com

PHPの2つの文字列の違いを強調表示します

PHPの2つの文字列の違いを強調する最も簡単な方法は何ですか?

Stack Overflowの編集履歴ページの行に沿って考えています。新しいテキストは緑色で、削除されたテキストは赤色です。利用可能な事前に記述された関数またはクラスがある場合、それは理想的です。

133
Philip Morton

PHP Horde_Text_Diff パッケージを使用できます。それはあなたのニーズに適しており、同様に非常にカスタマイズ可能です。

また、GPLの下でライセンスされているので、お楽しみください!

43
M.N

ある文字列を別の文字列に変換するための最小の(文字通りではない)編集数を計算するクラスを作成しました。

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

HTMLバージョンのdiffをレンダリングする静的関数があります。

これは最初のバージョンであり、改善される可能性がありますが、今のところうまく機能しているので、必要に応じて誰かがコンパクトな差分を効率的に生成する必要がある場合に備えて捨てています。

編集:現在Githubにあります: https://github.com/gorhill/PHP-FineDiff

74
R. Hill

堅牢なライブラリが必要な場合は、 Text_Diff (PEARパッケージ)がかなり良いようです。かなりクールな機能がいくつかあります。

25
Wickethewok

これもいいものです http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/

問題を解決するのは見た目ほど簡単ではなく、問題を理解するまで約1年間問題を悩ませました。 18行のコードで、PHPでアルゴリズムを作成できました。 diffを実行する最も効率的な方法ではありませんが、おそらく最も簡単に理解できます。

両方の文字列に共通する単語の最長シーケンスを検索し、部分文字列に共通の単語がなくなるまで、文字列の残りの最長シーケンスを再帰的に検索することで機能します。この時点で、残りの新しい単語を挿入として、残りの古い単語を削除として追加します。

ここからソースをダウンロードできます: PHP SimpleDiff ...

24
Softy

以下は、2つの配列を比較するために使用できる短い関数です。 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);
}

2つの配列を生成します。

  • 値の配列:差分に表示される要素のリスト。
  • マスク配列:数字が含まれます。 0:変更なし、-1:削除、1:追加。

配列に文字を入力すると、インライン差を計算するために使用できます。ここで、違いを強調するための1ステップだけです。

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タックOアーバーfファウルわーt

その他の注意事項:

  • Diffマトリックスには(m + 1)*(n + 1)個の要素が必要です。そのため、長いシーケンスを比較しようとすると、メモリ不足エラーが発生する可能性があります。この場合、最初に大きなチャンク(行など)を差分し、次に2番目のパスでその内容を差分します。
  • 一致する要素を最初と最後から切り取り、アルゴリズムを異なる中央でのみ実行すると、アルゴリズムを改善できます。 後の(より肥大化した)バージョン にもこれらの変更が含まれています。
16
Calmarius

XdiffにはPECL拡張機能もあります。

特に:

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

表示されている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);
  }
}
5
xgretsch

これは私が見つけた最高のものです。

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

enter image description here

4
Andy

探しているのは「差分アルゴリズム」です。簡単なGoogle検索で このソリューション に導かれました。私はそれをテストしませんでしたが、多分それはあなたが必要とすることをするでしょう。

3
Peter Bailey

PHPコアからこれらの素晴らしい関数を見ることをお勧めします。

similar_text — 2つの文字列間の類似度を計算する

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

levenshtein — 2つの文字列間のレーベンシュタイン距離を計算する

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

soundex —文字列のsoundexキーを計算する

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

metaphone —文字列のmetaphoneキーを計算する

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

2
Lukas

Neil Frasersのphpポートdiff_match_patch (Apache 2.0ライセンス)

2
hakre

PHP difflibに基づいたChris BoultonによるこのPython diffクラスに出会いました。

PHP Diff Lib

0
Shubhojoy Mitra