skip to Main Content

Hey There Developers I am Trying to Mark the changed words in two Strings i.e, I am trying to highlight the changed word in the string and display it in a box with green highlighted text and the old string in another box with red highlighted text This is the code I am using

<?php
function get_string_diff($old, $new, $get_similarity=false){
    // echo $old;
    $from_start = strspn($old ^ $new, "");        
    $from_end = strspn(strrev($old) ^ strrev($new), "");

    $old_end = strlen($old) - $from_end;
    $new_end = strlen($new) - $from_end;

    $start = substr($new, 0, $from_start);
    $end = substr($new, $new_end);
    $new_diff = substr($new, $from_start, $new_end - $from_start);  
    $old_diff = substr($old, $from_start, $old_end - $from_start);

    $new = "$start<ins style='background-color:#ccffcc'>$new_diff</ins>$end";
    $old = "$start<del style='background-color:#ffcccc'>$old_diff</del>$end";
    if($get_similarity)
    $get_similarity = "<ins style='background-color:#ccffcc'>$start $end</ins>"; 
    return array("old"=>$old, "new"=>$new);
}
$string_old = "This is the second div that we are using to check if the original data can be seen & Yes It is Working";
$string_new = "This is the first div that we are using to check if the changed data can be seen & Yes It is Working";
$diff = get_string_diff($string_old, $string_new,true);
echo "<center>
<h2>Old String VS New String</h2>
<table border=1 cellpadding=15>
    <tr align=center>
        <td>Old</td>
        <td>New</td>

    </tr>
    <tr>
        <td>".$diff['old']."</td>
        <td>".$diff['new']."</td>
        
    </tr>
</table></center>";
?>

Although it is working to some extent as the output is something like this enter image description here

The changed words in the strings are "Second" & "Original" So Ideally it should Highlight red only those two & not all the words between the two.

2

Answers


  1. As per your question trying to compare a word to a word you don’t need to use a substring to do so, it’s sufficient to compare a whole word to another. You can try the below function

        function get_string_diff($old, $new){
        //splitting each string to array of words in the sentence
        $old_parts = explode(" ",$old);
        $new_parts = explode(" ",$new);
        
        //using the counter of the while loop and having the limit the max number of words in either sentences
        $i = 0;
        $limit = max(count($old_parts),count($new_parts));
        
        //initializing empty string to be updated & returned
        $old_returned = "";
        $new_returned = "";
        
    while($i<$limit){
        //comparing a word to a word and cocnatenating its color based on the result
         if($old_parts[$i] == $new_parts[$i]){
            $old_returned .= ' <font color=008000>' . $old_parts[$i] . '</font>';
            $new_returned .= ' <font color=008000>' . $new_parts[$i] . '</font>';
        }
        else{
            $old_returned .= ' <font color=FF000000>' . $old_parts[$i] . '</font>';
            $new_returned .= ' <font color=FF000000>' . $new_parts[$i] . '</font>';
        }
        $i++;
        }
        return array("old"=>$old_returned, "new"=>$new_returned);
    }
    

    This is the tested output
    Testing Output

    Login or Signup to reply.
    • In order to find the difference between the two strings, we can consider each individual words as a single token and then do the comparison by exploding them on space character.

    • For comparison, we can go with finding the Longest Common Subsequence(LCS) among the 2 strings. This will yield us a minimal set of words that are different between the two strings which I presume is the most important for this task.

    • Once the LCS length is found, we will go with finding the actual words(set of tokens) which contribute to this length. These set of tokens will be common words among the 2 strings in order.

    • Our last step is to simply do a one-to-one comparison check with each word in old version of the string and in new version of the string. For old version of string, we will surround the not found token with del tags and ins for the new version. The common words will remain untouched as desired.

    Snippet:

    <?php
    
    function getDiffed($string_old, $string_new){
        $A = explode(" ", $string_old);
        $B = explode(" ", $string_new);
        
        $LCS = [];
        
        for($i = 0; $i < count($A); ++$i){
            for($j = 0; $j < count($B); ++$j){
                if($A[ $i ] == $B[ $j ]){
                    $LCS[ $i ][ $j ] = max($LCS[ $i ][ $j - 1 ] ?? 0, ($LCS[ $i - 1 ][ $j - 1 ] ?? 0) + 1);
                }else{
                    $LCS[ $i ][ $j ] = max($LCS[ $i - 1 ][ $j ] ?? 0, $LCS[ $i ][ $j - 1 ] ?? 0);
                }
            }
        }
        
        // get the LCS string space separated.
        
        $i = count($A) - 1;
        $j = count($B) - 1;
        $commonWords = [];
        
        while($i >= 0 && $j >= 0){
            if($A[ $i ] == $B[ $j ]){
                $commonWords[] = $A[ $i ];
                $i--; 
                $j--;
            }else if(($LCS[ $i ][$j - 1] ?? 0) > ($LCS[ $i - 1 ][ $j ] ?? 0)){
                $j--;
            }else{
                $i--;
            }
        }
        
        $commonWords = array_reverse($commonWords);
        
        // add red marks if any for the old string
        for($i = 0, $ptr = 0; $i < count($A); ++$i){
            if($ptr == count($commonWords) || $A[ $i ] !== $commonWords[ $ptr ]){
                $A[ $i ] = "<del style='background-color:#ffcccc'> " .$A[ $i ] . "</del>";
            }else{
                $ptr++;
            }
        }
        
        // add green marks if any for the new string
        for($i = 0, $ptr = 0; $i < count($B); ++$i){
            if($ptr == count($commonWords) || $B[ $i ] !== $commonWords[ $ptr ]){
                $B[ $i ] = "<ins style='background-color:#ccffcc'> " .$B[ $i ] . "</ins>";
            }else{
                $ptr++;
            }
        }
        
        
        return ['old' => implode(' ', $A), 'new' => implode(' ', $B)];
    } 
    

    Online Demo

    HTML View

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search