/** * Compares two files based initially on lines and then on words within the lines that * differ. * @param array $lines1 Array of ouwiki_line * @param array $lines2 Array of ouwiki_line * @return array (deleted,added); deleted and added are arrays of ouwiki_word with * position numbers from $lines1 and $lines2 respectively */ function ouwiki_diff_words($lines1, $lines2) { // Prepare arrays $deleted = array(); $added = array(); // Get line difference $linediff = ouwiki_diff(ouwiki_line::get_as_strings($lines1), ouwiki_line::get_as_strings($lines2)); // Handle lines that were entirely deleted foreach ($linediff->deletes as $deletedline) { $deleted = array_merge($deleted, $lines1[$deletedline]->words); } // And ones that were entirely added foreach ($linediff->adds as $addedline) { $added = array_merge($added, $lines2[$addedline]->words); } // Changes get diffed at the individual-word level foreach ($linediff->changes as $changerange) { // Build list of all words in each side of the range $file1words = array(); for ($index = $changerange->file1start; $index < $changerange->file1start + $changerange->file1count; $index++) { foreach ($lines1[$index]->words as $word) { $file1words[] = $word; } } $file2words = array(); for ($index = $changerange->file2start; $index < $changerange->file2start + $changerange->file2count; $index++) { foreach ($lines2[$index]->words as $word) { $file2words[] = $word; } } // Make arrays 1-based array_unshift($file1words, 'dummy'); unset($file1words[0]); array_unshift($file2words, 'dummy'); unset($file2words[0]); // Convert word lists into plain strings $file1strings = array(); foreach ($file1words as $index => $word) { $file1strings[$index] = $word->word; } $file2strings = array(); foreach ($file2words as $index => $word) { $file2strings[$index] = $word->word; } // Run diff on strings $worddiff = ouwiki_diff($file1strings, $file2strings); foreach ($worddiff->adds as $index) { $added[] = $file2words[$index]; } foreach ($worddiff->deletes as $index) { $deleted[] = $file1words[$index]; } foreach ($worddiff->changes as $changerange) { for ($index = $changerange->file1start; $index < $changerange->file1start + $changerange->file1count; $index++) { $deleted[] = $file1words[$index]; } for ($index = $changerange->file2start; $index < $changerange->file2start + $changerange->file2count; $index++) { $added[] = $file2words[$index]; } } } return array($deleted, $added); }
function test_diff_changes() { // Initial file for comparison (same for all examples) $file1 = array(1 => 'a', 'b', 'c', 'd', 'e', 'f', 'g'); // Add text at beginning $file2 = array(1 => '0', '1', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array(1, 2)); // Add text at end $file2 = array(1 => 'a', 'b', 'c', 'd', 'e', 'f', 'g', '0', '1'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array(8, 9)); // Add text in middle $file2 = array(1 => 'a', 'b', 'c', '0', '1', 'd', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array(4, 5)); // Delete text at beginning $file2 = array(1 => 'c', 'd', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array(1, 2)); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array()); // Delete text at end $file2 = array(1 => 'a', 'b', 'c', 'd', 'e'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array(6, 7)); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array()); // Delete text in middle $file2 = array(1 => 'a', 'b', 'c', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array(4, 5)); $this->assertEqual($result->changes, array()); $this->assertEqual($result->adds, array()); // Change text in middle (one line) $file2 = array(1 => 'a', 'b', 'frog', 'd', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 1); $this->assertEqual(array_values((array) $result->changes[0]), array(3, 1, 3, 1)); $this->assertEqual($result->adds, array()); // Change text in middle (two lines) $file2 = array(1 => 'a', 'b', 'frog', 'toad', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 1); $this->assertEqual(array_values((array) $result->changes[0]), array(3, 2, 3, 2)); $this->assertEqual($result->adds, array()); // Change text in middle (one line -> two) $file2 = array(1 => 'a', 'b', 'frog', 'toad', 'd', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 1); $this->assertEqual(array_values((array) $result->changes[0]), array(3, 1, 3, 2)); $this->assertEqual($result->adds, array()); // Change text in middle (two lines -> one) $file2 = array(1 => 'a', 'b', 'frog', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 1); $this->assertEqual(array_values((array) $result->changes[0]), array(3, 2, 3, 1)); $this->assertEqual($result->adds, array()); // Two changes $file2 = array(1 => 'a', 'frog', 'toad', 'c', 'd', 'zombie', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 2); $this->assertEqual(array_values((array) $result->changes[0]), array(2, 1, 2, 2)); $this->assertEqual(array_values((array) $result->changes[1]), array(5, 2, 6, 1)); $this->assertEqual($result->adds, array()); // Changes at ends $file2 = array(1 => 'ant', 'frog', 'toad', 'c', 'd', 'zombie'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array()); $this->assertEqual(count($result->changes), 2); $this->assertEqual(array_values((array) $result->changes[0]), array(1, 2, 1, 3)); $this->assertEqual(array_values((array) $result->changes[1]), array(5, 3, 6, 1)); $this->assertEqual($result->adds, array()); // A change, a delete, an add $file2 = array(1 => 'ant', 'b', 'd', 'zombie', 'e', 'f', 'g'); $result = ouwiki_diff($file1, $file2); $this->assertEqual($result->deletes, array(3)); $this->assertEqual(count($result->changes), 1); $this->assertEqual(array_values((array) $result->changes[0]), array(1, 1, 1, 1)); $this->assertEqual($result->adds, array(4)); }