[ Index ]
 

Code source de SPIP 1.8.3

Accédez au Source d'autres logiciels libres | Soutenez Angelica Josefina !

title

Body

[fermer]

/ecrire/ -> lab_diff.php (source)

   1  <?php
   2  
   3  /***************************************************************************\
   4   *  SPIP, Systeme de publication pour l'internet                           *
   5   *                                                                         *
   6   *  Copyright (c) 2001-2005                                                *
   7   *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
   8   *                                                                         *
   9   *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  10   *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
  11  \***************************************************************************/
  12  
  13  
  14  // Ce fichier ne sera execute qu'une fois
  15  if (defined("_ECRIRE_INC_DIFF")) return;
  16  define("_ECRIRE_INC_DIFF", "1");
  17  
  18  
  19  //
  20  // LCS (Longest Common Subsequence) en deux versions
  21  // (ref: http://www2.toki.or.id/book/AlgDesignManual/BOOK/BOOK5/NODE208.HTM)
  22  
  23  // Version ultra-simplifiee : chaque chaine est une permutation de l'autre 
  24  // et on passe en parametre un des deux tableaux de correspondances
  25  function lcs_opt($s) {
  26      $n = count($s);
  27      if (!$n) return array();
  28      $paths = array();
  29      $paths_ymin = array();
  30      $max_len = 0;
  31  
  32      // Insertion des points
  33      asort($s);
  34      foreach ($s as $y => $c) {
  35          for ($len = $max_len; $len > 0; $len--) {
  36              if ($paths_ymin[$len] < $y) {
  37                  $paths_ymin[$len + 1] = $y;
  38                  $paths[$len + 1] = $paths[$len];
  39                  $paths[$len + 1][$y] = $c;
  40                  break;
  41              }
  42          }
  43          if ($len == 0) {
  44              $paths_ymin[1] = $y;
  45              $paths[1] = array($y => $c);
  46          }
  47          if ($len + 1 > $max_len) $max_len = $len + 1;
  48      }
  49      return $paths[$max_len];
  50  }
  51  
  52  // Version normale : les deux chaines n'ont pas ete traitees au prealable
  53  // par la fonction d'appariement
  54  function lcs($s, $t) {
  55      $n = count($s);
  56      $p = count($t);
  57      if (!$n || !$p) return array(0 => array(), 1 => array());
  58      $paths = array();
  59      $paths_ymin = array();
  60      $max_len = 0;
  61      $s_pos = $t_pos = array();
  62  
  63      // Insertion des points
  64      foreach ($t as $y => $c) $t_pos[trim($c)][] = $y;
  65  
  66      foreach ($s as $x => $c) {
  67          $c = trim($c);
  68          if (!$t_pos[$c]) continue;
  69          krsort($t_pos[$c]);
  70          foreach ($t_pos[$c] as $y) {
  71              for ($len = $max_len; $len > 0; $len--) {
  72                  if ($paths_ymin[$len] < $y) {
  73                      $paths_ymin[$len + 1] = $y;
  74                      // On construit le resultat sous forme de chaine d'abord,
  75                      // car les tableaux de PHP sont dispendieux en taille memoire
  76                      $paths[$len + 1] = $paths[$len]." $x,$y";
  77                      break;
  78                  }
  79              }
  80              if ($len + 1 > $max_len) $max_len = $len + 1;
  81              if ($len == 0) {
  82                  $paths_ymin[1] = $y;
  83                  $paths[1] = "$x,$y";
  84              }
  85          }
  86      }
  87      if ($paths[$max_len]) {
  88          $path = explode(" ", $paths[$max_len]);
  89          $u = $v = array();
  90          foreach ($path as $p) {
  91              list($x, $y) = explode(",", $p);
  92              $u[$x] = $y;
  93              $v[$y] = $x;
  94          }
  95          return array($u, $v);
  96      }
  97      return array(0 => array(), 1 => array());
  98  }
  99  
 100  
 101  function test_lcs($a, $b) {
 102      $s = explode(" ", $a);
 103      $t = explode(" ", $b);
 104      
 105      $t0 = explode(" ", microtime());
 106      list($r1, $r2) = lcs($s, $t);
 107      $t1 = explode(" ", microtime());
 108      $dt = $t1[0] + $t1[1] - $t0[0] - $t0[1];
 109      echo join(" ", $r1)."<br />";
 110      echo join(" ", $r2)."<p>";
 111      echo "<div style='font-weight: bold; color: red;'>$dt s.</div>";
 112  }
 113  
 114  function test_lcs_opt($s) {
 115      $s = preg_split(',\s+,', $s);
 116  
 117      $t0 = explode(" ", microtime());
 118      $t = lcs_opt($s);
 119      $t1 = explode(" ", microtime());
 120      $dt = $t1[0] + $t1[1] - $t0[0] - $t0[1];
 121      echo join(" ", $s)."<br />";
 122      echo join(" ", $t)."<p>";
 123      echo "<div style='font-weight: bold; color: red;'>$dt s.</div>";
 124  }
 125  
 126  
 127  //
 128  // Generation de diff a plusieurs etages
 129  //
 130  
 131  class Diff {
 132      var $diff;
 133      var $fuzzy;
 134  
 135  	function Diff($diff) {
 136          $this->diff = $diff;
 137          $this->fuzzy = true;
 138      }
 139  
 140  	function comparer($new, $old) {
 141          $paras = $this->diff->segmenter($new);
 142          $paras_old = $this->diff->segmenter($old);
 143          if ($this->diff->fuzzy()) {
 144              list($trans_rev, $trans) = apparier_paras($paras_old, $paras);
 145              $lcs = lcs_opt($trans);
 146              $lcs_rev = array_flip($lcs);
 147          }
 148          else {
 149              list($trans_rev, $trans) = lcs($paras_old, $paras);
 150              $lcs = $trans;
 151              $lcs_rev = $trans_rev;
 152          }
 153      
 154          reset($paras_old);
 155          reset($paras);
 156          reset($lcs);
 157          unset($i_old);
 158          $fin_old = false;
 159          foreach ($paras as $i => $p) {
 160              if (!isset($trans[$i])) {
 161                  // Paragraphe ajoute
 162                  $this->diff->ajouter($p);
 163                  continue;
 164              }
 165              $j = $trans[$i];
 166              if (!isset($lcs[$i])) {
 167                  // Paragraphe deplace
 168                  $this->diff->deplacer($p, $paras_old[$j]);
 169                  continue;
 170              }
 171              if (!$fin_old) {
 172                  // Paragraphes supprimes jusqu'au paragraphe courant
 173                  if (!isset($i_old)) {
 174                      list($i_old, $p_old) = each($paras_old);
 175                      if (!$p_old) $fin_old = true;
 176                  }
 177                  while (!$fin_old && $i_old < $j) {
 178                      if (!isset($trans_rev[$i_old])) {
 179                          $this->diff->supprimer($p_old);
 180                      }
 181                      unset($i_old);
 182                      list($i_old, $p_old) = each($paras_old);
 183                      if (!$p_old) $fin_old = true;
 184                  }
 185              }
 186              // Paragraphe n'ayant pas change de place
 187              $this->diff->comparer($p, $paras_old[$j]);
 188          }
 189          // Paragraphes supprimes a la fin du texte
 190          if (!$fin_old) {
 191              if (!isset($i_old)) {
 192                  list($i_old, $p_old) = each($paras_old);
 193                  if (!strlen($p_old)) $fin_old = true;
 194              }
 195              while (!$fin_old) {
 196                  if (!isset($trans_rev[$i_old])) {
 197                      $this->diff->supprimer($p_old);
 198                  }
 199                  list($i_old, $p_old) = each($paras_old);
 200                  if (!$p_old) $fin_old = true;
 201              }
 202          }
 203          if (isset($i_old)) {
 204              if (!isset($trans_rev[$i_old])) {
 205                  $this->diff->supprimer($p_old);
 206              }
 207          }
 208          return $this->diff->resultat();
 209      }
 210  }
 211  
 212  class DiffTexte {
 213      var $r;
 214  
 215  	function DiffTexte() {
 216          $this->r = "";
 217      }
 218  
 219  	function _diff($p, $p_old) {
 220          $diff = new Diff(new DiffPara);
 221          return $diff->comparer($p, $p_old);
 222      }
 223  
 224  	function fuzzy() {
 225          return true;
 226      }
 227  	function segmenter($texte) {
 228          return separer_paras($texte);
 229      }
 230  
 231      // NB :  rem=\"diff-\" est un signal pour la fonction "afficher_para_modifies"
 232  	function ajouter($p) {
 233          $p = trim($p);
 234          $this->r .= "\n\n\n<div class=\"diff-para-ajoute\" title=\""._T('diff_para_ajoute')."\">".$p."</div rem=\"diff-\">";
 235      }
 236  	function supprimer($p_old) {
 237          $p_old = trim($p_old);
 238          $this->r .= "\n\n\n<div class=\"diff-para-supprime\" title=\""._T('diff_para_supprime')."\">".$p_old."</div rem=\"diff-\">";
 239      }
 240  	function deplacer($p, $p_old) {
 241          $this->r .= "\n\n\n<div class=\"diff-para-deplace\" title=\""._T('diff_para_deplace')."\">";
 242          $this->r .= trim($this->_diff($p, $p_old));
 243          $this->r .= "</div rem=\"diff-\">";
 244      }
 245  	function comparer($p, $p_old) {
 246          $this->r .= "\n\n\n".$this->_diff($p, $p_old);
 247      }
 248      
 249  	function resultat() {
 250          return $this->r;
 251      }
 252  }
 253  
 254  class DiffPara {
 255      var $r;
 256  
 257  	function DiffPara() {
 258          $this->r = "";
 259      }
 260  
 261  	function _diff($p, $p_old) {
 262          $diff = new Diff(new DiffPhrase);
 263          return $diff->comparer($p, $p_old);
 264      }
 265  
 266  	function fuzzy() {
 267          return true;
 268      }
 269  	function segmenter($texte) {
 270          $paras = array();
 271          $texte = trim($texte);
 272          while (preg_match('/[\.!\?]+\s*/u', $texte, $regs)) {
 273              $p = strpos($texte, $regs[0]) + strlen($regs[0]);
 274              $paras[] = substr($texte, 0, $p);
 275              $texte = substr($texte, $p);
 276          }
 277          if ($texte) $paras[] = $texte;
 278          return $paras;
 279      }
 280  
 281  	function ajouter($p) {
 282          $this->r .= "<span class=\"diff-ajoute\" title=\""._T('diff_texte_ajoute')."\">".$p."</span rem=\"diff-\">";
 283      }
 284  	function supprimer($p_old) {
 285          $this->r .= "<span class=\"diff-supprime\" title=\""._T('diff_texte_supprime')."\">".$p_old."</span rem=\"diff-\">";
 286      }
 287  	function deplacer($p, $p_old) {
 288          $this->r .= "<span class=\"diff-deplace\" title=\""._T('diff_texte_deplace')."\">".$this->_diff($p, $p_old)."</span rem=\"diff-\">";
 289      }
 290  	function comparer($p, $p_old) {
 291          $this->r .= $this->_diff($p, $p_old);
 292      }
 293      
 294  	function resultat() {
 295          return $this->r;
 296      }
 297  }
 298  
 299  class DiffPhrase {
 300      var $r;
 301  
 302  	function DiffPhrase() {
 303          $this->r = "";
 304      }
 305  
 306  	function fuzzy() {
 307          return false;
 308      }
 309  	function segmenter($texte) {
 310          $paras = array();
 311          if (test_pcre_unicode()) {
 312              $punct = '([[:punct:]]|'.plage_punct_unicode().')';
 313              $mode = 'u';
 314          }
 315          else {
 316              // Plages de poncutation pour preg_match bugge (ha ha)
 317              $punct = '([^\w\s\x80-\xFF]|'.plage_punct_unicode().')';
 318              $mode = '';
 319          }
 320          $preg = '/('.$punct.'+)(\s+|$)|(\s+)('.$punct.'*)/'.$mode;
 321          while (preg_match($preg, $texte, $regs)) {
 322              $p = strpos($texte, $regs[0]);
 323              $l = strlen($regs[0]);
 324              $punct = $regs[1] ? $regs[1] : $regs[6];
 325              $milieu = "";
 326              if ($punct) {
 327                  // Attacher les raccourcis fermants au mot precedent
 328                  if (preg_match(',^[\]}]+$,', $punct)) {
 329                      $avant = substr($texte, 0, $p) . $regs[5] . $punct;
 330                      $texte = $regs[4] . substr($texte, $p + $l);
 331                  }
 332                  // Attacher les raccourcis ouvrants au mot suivant
 333                  else if ($regs[5] && preg_match(',^[\[{]+$,', $punct)) {
 334                      $avant = substr($texte, 0, $p) . $regs[5];
 335                      $texte = $punct . substr($texte, $p + $l);
 336                  }
 337                  // Les autres signes de ponctuation sont des mots a part entiere
 338                  else {
 339                      $avant = substr($texte, 0, $p);
 340                      $milieu = $regs[0];
 341                      $texte = substr($texte, $p + $l);
 342                  }
 343              }
 344              else {
 345                  $avant = substr($texte, 0, $p + $l);
 346                  $texte = substr($texte, $p + $l);
 347              }
 348              if ($avant) $paras[] = $avant;
 349              if ($milieu) $paras[] = $milieu;
 350          }
 351          if ($texte) $paras[] = $texte;
 352          return $paras;
 353      }
 354  
 355  	function ajouter($p) {
 356          $this->r .= "<span class=\"diff-ajoute\" title=\""._T('diff_texte_ajoute')."\">".$p."</span rem=\"diff-\"> ";
 357      }
 358  	function supprimer($p_old) {
 359          $this->r .= "<span class=\"diff-supprime\" title=\""._T('diff_texte_supprime')."\">".$p_old."</span rem=\"diff-\"> ";
 360      }
 361  	function comparer($p, $p_old) {
 362          $this->r .= $p;
 363      }
 364  
 365  	function resultat() {
 366          return $this->r;
 367      }
 368  }
 369  
 370  
 371  function preparer_diff($texte) {
 372      include_spip("charsets.php");
 373  
 374      $charset = lire_meta('charset');
 375      if ($charset == 'utf-8')
 376          return unicode_to_utf_8(html2unicode($texte));
 377      return unicode_to_utf_8(html2unicode(charset2unicode($texte, $charset, true)));
 378  }
 379  
 380  function afficher_diff($texte) {
 381      $charset = lire_meta('charset');
 382      if ($charset == 'utf-8') return $texte;
 383      return charset2unicode($texte, 'utf-8');
 384  }
 385  
 386  
 387  ?>


Généré le : Thu Feb 22 22:27:47 2007 par Balluche grâce à PHPXref 0.7