Ver Mensaje Individual
  #33 (permalink)  
Antiguo 10/07/2010, 14:49
Avatar de pateketrueke
pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años
Puntos: 2534
Respuesta: [Desafío PHP] Función reduce()

Triby
Código PHP:
Ver original
  1. function reduce ($str) {
  2.     // Patrón para comparación
  3.     $letters = 'abcdefghijklmnopqrstuvwxyz';
  4.     // Dirección actual
  5.     $dir = 'no';
  6.     // Longitud  de la cadena original
  7.     $strlen = strlen($str) - 1;
  8.      // Primer caracter directo
  9.     $reduce = $str[0];
  10.     // Iniciamos desde el segundo
  11.     for ($i = 1; $i <= $strlen; $i++):
  12.         // Caracter actual y su posición en el patrón
  13.         $char = $str[$i];
  14.         $pos = strpos($letters, $char);
  15.         // Caracter anterior en $str y su posición
  16.         $lastchar = $str[$i - 1];
  17.         $lastpos = strpos($letters, $lastchar);
  18.  
  19.         // Secuencia y dirección?
  20.         if ($pos == ($lastpos + 1)  && ($dir == 'left' || $dir == 'no')):
  21.             // Secuencia izq
  22.             $dir = 'left';
  23.             if ($i < $strlen):
  24.                 // Si no es el último caracter
  25.                 continue;
  26.             endif;
  27.         elseif ($pos == ($lastpos - 1) && ($dir == 'right' || $dir == 'no')):
  28.             // Secuencia der
  29.             $dir = 'right';
  30.             if ($i < $strlen):
  31.                 // Si no es el último caracter
  32.                 continue;
  33.             endif;
  34.         elseif ($dir == 'no'):
  35.             // No hay secuencia
  36.             $reduce .= $char;
  37.             continue;
  38.         endif;
  39.         // Por default
  40.         $reverse = false;
  41.         // Cambio de sentido?
  42.         if ($i < $strlen):
  43.             // Siguiente caracter y posición para verificar
  44.             $newchar = $str[$i + 1];
  45.             $newpos = strpos($letters, $newchar);
  46.             // Cambio de dirección?
  47.             $reverse = (($dir == 'left' && $pos == ($newpos + 1) && $lastpos == ($newpos + 2))
  48.                 || ($dir == 'right' && $pos == ($newpos - 1) && $lastpos == ($newpos - 2)));
  49.             if ($reverse):
  50.                 // Aplicamos la nueva dirección
  51.                 $dir = ($pos == ($newpos - 1)) ? 'left' : 'right';
  52.             else:
  53.                 // Cancelamos dirección anterior
  54.                 $dir = 'no';
  55.             endif;
  56.         else:
  57.             $dir = 'no';
  58.         endif;
  59.         // Fin de secuencia y/o cambio de dirección
  60.  
  61.         // Posición del último caracter de $reduce
  62.         $redpos = strpos($letters, $reduce[strlen($reduce) - 1]);
  63.         // Verificamos cantidad caracteres
  64.         $abs = abs($redpos - $lastpos);
  65.  
  66.         // Último caracter de $str
  67.         if ($i == $strlen):
  68.             if ($abs == 0):
  69.                 // No hay secuencia
  70.                 $reduce .= $char;
  71.             elseif (abs($pos - $lastpos) != 1):
  72.                 // No hay secuencia, quedaba pendiente caracter anterior
  73.                 $reduce .= "-{$lastchar}{$char}";
  74.             else:
  75.                 // Sí hay secuencia
  76.                 $reduce .= "-{$char}";
  77.             endif;
  78.         elseif ($abs > 1):
  79.             // Secuencia más de 2 caracteres
  80.             // ? - Cambio, omite el caracter actual
  81.             // : - No cambio, se agregan guión, último y caracter actual
  82.             $reduce .= ($reverse) ? "-{$lastchar}" : "-{$lastchar}{$char}";
  83.         else:
  84.             // Secuencia es de sólo dos caracteres   ab
  85.             // ? - Cambio, se omite el caracter actual
  86.             // : - No cambio, se agregan último y caracter actual
  87.             $reduce .= ($reverse) ? $lastchar : "{$lastchar}{$char}";
  88.         endif;
  89.     endfor;
  90.     return $reduce;
  91. }

Otro script que usa cadenas auxiliares para comprobar el rango, y que tampoco entiendo del todo.

Cabe mencionar que realmente es complicado traducir un algoritmo mental en código claro, esto es cierto también pero comprender el proceso inverso es realmente complicado, sino hasta difícil. (:

Es interesante la sintaxis que se utiliza en este script, desde versiones alternativas de keywords para control de flujo, aka. endif, endfor, etc.. así como también un uso correcto y casi magistral de variables, comparaciones, comillas y comentarios.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.