sourcecode

PHP에서 두 문자열의 차이를 강조 표시합니다.

copyscript 2022. 9. 26. 21:54
반응형

PHP에서 두 문자열의 차이를 강조 표시합니다.

PHP에서 두 문자열의 차이를 강조하는 가장 쉬운 방법은 무엇입니까?

Stack Overflow 편집 이력 페이지의 새로운 텍스트는 녹색으로, 삭제된 텍스트는 빨간색으로 되어 있습니다.미리 작성된 함수나 클래스가 있다면 이상적입니다.

한 문자열을 다른 문자열로 변환하기 위해 최소 편집 횟수(문자 그대로 사용할 수 없음)를 계산하는 클래스를 작성했습니다.

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

diff의 HTML 버전을 렌더링하는 정적 함수를 가지고 있습니다.

첫 번째 버전으로 개선될 것 같습니다만, 현시점에서는 정상적으로 동작하고 있기 때문에, 누군가 필요에 따라서 콤팩트 diff를 효율적으로 생성해야 할 경우에 대비해 버립니다.

편집: 현재 Github에 있습니다.https://github.com/gorhill/PHP-FineDiff

PHP Horde_Text_Diff 패키지를 사용할 수 있었습니다.

그러나 이 패키지는 더 이상 사용할 수 없습니다.

이것은 좋은 것입니다.http://paulbutler.org/archives/a-simple-diff-algorithm-in-php/도 마찬가지입니다.

그 문제를 해결하는 것은 보기만큼 간단하지 않고, 내가 그것을 알기 전까지 약 1년 동안 그 문제가 나를 괴롭혔다.18줄의 코드로 PHP로 알고리즘을 작성했습니다.이 방법이 가장 효율적인 방법은 아니지만 가장 이해하기 쉬운 방법이 될 수 있습니다.

두 문자열에 공통되는 가장 긴 단어의 시퀀스를 찾아 하위 문자열에 공통 단어가 없을 때까지 문자열의 나머지 가장 긴 시퀀스를 재귀적으로 찾는 방식으로 작동합니다.이 시점에서 나머지 새 단어는 삽입으로, 나머지 오래된 단어는 삭제로 추가됩니다.

PHP SimpleDiff에서 소스를 다운로드할 수 있습니다.

견고한 라이브러리를 원한다면 Text_Diff(PEAR 패키지)가 좋습니다.그것은 꽤 멋진 특징들을 가지고 있다.

여기에서는, 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개의 어레이를 생성합니다.

  • values array :diff에 표시되는 요소의 리스트.
  • mask array:에는 숫자가 포함되어 있습니다.0: 변경되지 않음, -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> 

StackOerverfFaulowt

기타 주의사항:

  • diff 매트릭스에는 (m+1)*(n+1) 요소가 필요합니다.따라서 긴 시퀀스를 분산하려고 하면 메모리 부족 오류가 발생할 수 있습니다.이 경우 큰 청크(예: 라인)를 먼저 구별한 다음 두 번째 경로로 내용을 구별합니다.
  • 처음부터 끝까지 일치하는 요소를 트리밍한 다음 다른 중간에서만 알고리즘을 실행하면 알고리즘이 개선될 수 있습니다.후자의 버전(더 비대해진 버전)에도 이러한 변경이 포함되어 있습니다.

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

이게 내가 찾은 것 중 최고야.

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

여기에 이미지 설명 입력

PEAR 베이스의 옵션과 표시된 심플한 옵션의 양쪽 모두에 큰 문제가 있었습니다.여기 Unix diff 명령어를 활용하는 솔루션이 있습니다(유닉스 시스템에 있거나 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);
  }
}

당신이 찾고 있는 것은 "diff algorithm"입니다.빠른 구글 검색을 통해 이 솔루션을 찾을 수 있었습니다.테스트하진 않았지만, 아마 당신이 원하는 대로 할 수 있을 거예요.

Neil Frasers diff_match_patch의 php 포트(Apache 2.0 라이선스)

PHP 코어에서 다음과 같은 놀라운 기능을 볼 것을 권장합니다.

silar_text : 두 문자열 간의 유사도를 계산합니다.

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

levenshtein : 2개의 문자열 사이의 Levenshtein 거리를 계산합니다.

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개와 컬러 스타일링으로 심플한 어프로치를 시도했습니다.주의: diff checker는 단어의 차이만 강조 표시하고 문자는 강조 표시하지 않습니다.

    <?php
    $valueOne = $_POST['value'] ?? "";
    $valueTwo = $_POST['valueb'] ?? "" ;
    
    $trimValueOne = trim($valueOne);
    $trimValueTwo = trim($valueTwo);

    $arrayValueOne = explode(" ",$trimValueOne);
    $arrayValueTwo = explode(" ",$trimValueTwo);

    $allDiff = array_merge(array_diff($arrayValueOne, $arrayValueTwo), array_diff($arrayValueTwo, $arrayValueOne));
    if(array_intersect($arrayValueOne,$allDiff) && array_intersect($arrayValueTwo,$allDiff)){

        if(array_intersect($arrayValueOne,$allDiff)){
            $highlightArr = array_intersect($arrayValueOne,$allDiff);
            $highlightArrValue = array_values($highlightArr);
            for ($i=0; $i <count($arrayValueOne) ;$i++) { 
                for ($j=0; $j <count($highlightArrValue) ; $j++) { 
                    if($arrayValueOne[$i] == $highlightArrValue[$j]){
                        $arrayValueOne[$i] = "<span>".$arrayValueOne[$i]."</span>";
                    }
                }
            }
            $strOne = implode(" ",$arrayValueOne);
            echo "<p class = \"one\">{$strOne}</p>";
        }if(array_intersect($arrayValueTwo,$allDiff)){
        $highlightArr = array_intersect($arrayValueTwo,$allDiff);
        $highlightArrValue = array_values($highlightArr);
        for ($i=0; $i <count($arrayValueTwo) ;$i++) { 
            for ($j=0; $j <count($highlightArrValue) ; $j++) { 
                    if($arrayValueTwo[$i] == $highlightArrValue[$j]){
                        $arrayValueTwo[$i] = "<span>".$arrayValueTwo[$i]."</span>";
                    }
                }
        }
        $strTwo = implode(" ",$arrayValueTwo);
        echo "<p class = \"two\">{$strTwo}</p>";
        }
    }elseif(!(array_intersect($arrayValueOne,$allDiff) && array_intersect($arrayValueTwo,$allDiff))){
        if($trimValueOne == $trimValueTwo){
            echo"<p class = \"one green\">$trimValueOne</p></p>";
            echo"<p class = \"two green\">$trimValueTwo</p></p>";
        }
        else{
            echo"<p class = \"one \">$trimValueOne</p></p>";
            echo"<p class = \"two \">$trimValueTwo</p></p>";
        }

    }
?>


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <form method="post" action="">
    <textarea type="text" name="value" placeholder="enter first text"></textarea>
    <textarea type="text" name="valueb" placeholder="enter second text"></textarea>
    <input type="submit">
    </form>
</body>
</html>

Python difflib에 기반한 Chris Boulton의 PHP diff 클래스는 좋은 해결책이 될 수 있습니다.

PHP Diff Lib

또 다른 솔루션(통합 뷰가 아닌 나란히 비교) : https://github.com/danmysak/side-by-side

문자열 B가 아닌 문자열 A에서 문자를 찾는 매우 간단한 함수를 찾고 있는 분들을 위해 이 빠르고 간단한 함수를 작성했습니다.

function strdiff($a,$b){

    $a = str_split($a);
    $b = str_split($b);

    return array_diff($a,$b);

}

안녕하세요, 이것이 많은 도움이 될 것입니다.

$old_data = "We'll of today's hunt we will find inner zen. You are awesome [TEAM_NAME]! Cleveland has a lot more to offer though, so keep on roaming and find some happiness with Let's Roam!;";
$new_data = "We'll of today's hunt we will find inner zen. Great job today, you are freaking super awesome [TEAM_NAME]! though, so keep roaming Cleveland has a lot more to offer and find happiness on www.letsroam.com!;";

if($old_data) {
  $old_words = explode(" " , $old_data);
  $new_words = explode(" ", $new_data);

  $added_words = array();
  $deleted_words = array();
  $unchanged_words = array();
  foreach($new_words as $new_word) {
      $new_word_index = array_search($new_word, $old_words);
      // if($new_word == "you"){
      //   die_r(array());
      // }
      if( $new_word_index > -1) {
          // word already exists
          array_push($unchanged_words, $new_word);
          unset($old_words[$new_word_index]);
      } else {
          // word does not already exists
          array_push($added_words, $new_word);
      } 
      
   }
 $deleted_words = $old_words;
 $added_word_count = count($added_words);
 $added_word_characters = strlen(implode(" ", $added_words));
}
die_r(array(
  "old_data"=> $old_data,
  "new_data"=> $new_data,
  "unchanged_words"=> $unchanged_words,
  "added_words"=> $added_words,
  "deleted_words"=> $deleted_words,
  "added_word_count"=>$added_word_count,
  "added_word_characters"=>$added_word_characters
));

언급URL : https://stackoverflow.com/questions/321294/highlight-the-difference-between-two-strings-in-php

반응형