Karakter alapú szöveg-összehasonlítás PHP-vel

Tartalom

Bevezető

Készülve a csütörtöki diplomavédésre, megnéztem a bíráló által feltett kérdéseket. Diplomatervem egy adatbázis séma alapú PHP kódgenerátor. (Később majd írok erről egy részletes post-ot.) A bíráló egyik kérdése volt, hogy a generált forráskód hány százalékát kell átírni egy valós környezetben.

Ez egy nagyon jó kérdés, bennem is felmerült már. Forráskód bázis rendelkezésre áll, úgyhogy van kód amin meg lehet mérni. Első ötlet lehet a diff parancs. De ebben az esetben problémás lehet, hogy a diff soronként vizsgálja a forráskódot. Ez két dolog miatt gond:

  • A generált kódban vannak felesleges blokkok, amelyeket nem töröltem hanem a // jelekkel kommenteztem ki.
  • Minden táblához létrejön egy konfigurációs fájl, amelynek az a célja, hogy testreszabáskor módosítsák. Minden sorát!

Ez a két eset nagyon gyakori, ezért a soronként összehasonlítás alapján megítélni a forráskód-generátor jóságát félrevezető lenne.

Egy karakter alapú összehasonlítás ennél sokkal pontosabb információt adna. Kicsit kutattam az interneten és találtam egy megoldást, amit kicsit átírva született a lenti kód.

Karakter alapú szöveg-összehasonlító PHP szkript

A lenti szkript definiál egy CharDiff osztályt, amit a PEAR Text_Diff csomagban található Text_MappedDiff osztályból öröklődik. A Text_MappedDiff pedig a Text_Diff-ből öröklődik, tehát a lenti osztály egyben Text_Diff osztályú is. Ez azért jó, mert a fent említett csomagban van jónéhány renderer, amelyekkel különböző szabványos patch kimeneteket lehet generálni.

De szerettem volna vizualizálni is a dolgot, ezért az osztály része egy render metódus ami HTML kimenetet ad, és grafikusan ábrázolja a a különbséget a két szöveg között.

Eredeti kód: www.hawkee.com

Íme a kód, CharDiff.php:

<?php
/**
 * Karakter alapú szövegösszehasonlító
 * -----------------------------------
 * Használat:
 * $text1 = 'árvíztűrő tükörfúrógép';
 * $text2 = 'árvíztörő tükörfúrógép';
 *
 * $diff = new CharDiff($text1, $text2);
 *
 * $diff->render();
 */

require_once 'Text/Diff.php';

class
CharDiff extends Text_MappedDiff {

  function
CharDiff ($text_src, $text_tgt) {

   
$chars_src = str_split($text_src, 1);
   
$chars_tgt = str_split($text_tgt, 1);

   
$chars_src_mapped = $chars_src;
   
$chars_tgt_mapped = $chars_tgt;

     
parent::Text_MappedDiff($chars_src, $chars_tgt, $chars_src_mapped, $chars_tgt_mapped);
  }

  function
getStat() {
   
$stat = array();

   
$stat['copy']  = 0;
   
$stat['add']  = 0;
   
$stat['del']  = 0;
   
$stat['change']  = 0;
   
$stat['change-del']  = 0;
   
$stat['change-add']  = 0;

    foreach(
$this->getDiff() as $op) {
      if (
is_a($op, 'Text_Diff_Op_copy')) $stat['copy'] += $op->norig();
      if (
is_a($op, 'Text_Diff_Op_delete')) $stat['del'] += $op->norig();
      if (
is_a($op, 'Text_Diff_Op_add')) $stat['add'] += $op->nfinal();
      if (
is_a($op, 'Text_Diff_Op_change')) { $stat['change-del'] += $op->norig(); $stat['change-add'] += $op->nfinal(); }
    }

    return
$stat;
  }

  function
render($color_delete = 'red', $color_add = 'green') {
    foreach (
$this->getDiff() as $op) {
      if (
is_a(&$op,'Text_Diff_Op_copy')) {
        echo
$this->_implode($op->final);
      }
      elseif (
is_a(&$op,'Text_Diff_Op_delete')) {
        echo
'<span style="background-color: ', $color_delete, ';">', $this->_implode($op->orig), '</span>';
      }
      elseif (
is_a(&$op,'Text_Diff_Op_add')) {
        echo
'<span style="background-color: ', $color_add.';">', $this->_implode($op->final), '</span>';
      }
      elseif (
is_a(&$op,'Text_Diff_Op_change')) {
        echo
'<span style="background-color: ', $color_delete.';">', $this->_implode($op->orig), '</span>';
        echo
'<span style="background-color: ', $color_add.';">', $this->_implode($op->final), '</span>';
      }
    }
   
    return
$return;
  }

  function
_implode($chars) {
    return
nl2br( implode('', array_map( array($this, '_htmlFilter'), $chars) ) );
  }

 
// used with array_map
 
function _htmlFilter($text) {
    return
$text = str_replace( array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $text);
  }

}
?>

A feneti kód letölthető itt: [attachment:CharDiff.php.txt=CharDiff.php]

Az osztály használata:

<?php
  $text1
= 'árvíztűrő tükörfúrógép';
 
$text2 = 'árvíztörő tükörfúrógép';

 
$diff = new CharDiff($text1, $text2);

 
$diff->render();
?>

Remélem lesz aki hasznosnak találja majd.

CsatolmányMéret
Plain text icon CharDiff.php.txt2.38 KB

1262 hozzászólás