• Publicidad

Ejercicio: encontrar la subcadena más larga

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Ejercicio: encontrar la subcadena más larga

Notapor elesar » 2011-12-19 21:30 @937

Hola, soy nuevo en Perl, y necesitaría saber si alguien me puede ayudar a resolver el siguiente ejercicio:

"Leer de un archivo ya existente una cadena muy larga de caracteres, encontrar la subcadena repetida más larga."

Ejemplo:

$cadena="12345ja12345jaxd12345jaxd1117";

la subcadena "12345jaxd" de $cadena es la más larga repetida.

No sé cómo hacer para recorrer la cadena carácter por carácter e ir viendo si se repite en algún lado. Si alguien me puede ayudar con esto se lo agradecería mucho.

Muchas gracias. Saludos
elesar
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2011-12-19 20:33 @898

Publicidad

Re: Ejercicio: encontrar la subcadena más larga

Notapor explorer » 2011-12-19 22:01 @959

Bienvenido a los foros de Perl en español, elesar.

Pues se trata de un ejercicio interesante...

Un poco de matemáticas... Si la longitud de la cadena es l, entonces la cadena más larga que se puede repetir es de longitud l/2, y además, comenzará siempre en la posición 0.

O sea, que tenemos que buscar cadenas de longitud creciente, desde 1 a l/2.

La búsqueda de cadenas repetidas es mejor hacerla con la función index(), indicando la posición de la siguiente búsqueda.

Las cadenas que más se repiten las puedes guardar en hash, pero el caso es que solo nos piden un máximo, así que con el viejo sistema de guardar en una variable las veces que aparece el máximo, y en otra, qué máximo es, lo tenemos hecho.

P.D. Por aquí no 'solemos' resolver trabajos de clase. Pero sí resolvemos dudas de Perl. Quizás alguien se anime y te da una solución, pero lo ideal es que muestres antes algo de código.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ejercicio: encontrar la subcadena más larga

Notapor elesar » 2011-12-20 20:05 @878

Gracias, hice algo de código pero está muy incompleto y en la variable $subcadena me da 0.

Te adjunto acá el código que hice:

#!c:/perl/bin/perl.exe
open(CADENA,"C:/cadena.txt") || die "No se encuentra el archivo";
$linea=<CADENA>;
print $linea;
close(CADENA);
$subcadena="";
$aux="";
$e=-1;
@array=split("",$linea);
foreach $letra(@array){
$e++;
for($e;$i<@array.length;$i++){
$subcadena=$subcadena+$array[$e+1]; # acá intento cargar la siguiente letra del array a la subcadena, pero no lo hace, quiero cargarlo como si fuera agregar un carácter
if(length($subcadena) gt $aux ){ # acá falta preguntar o buscar si se repite la cadena
$aux=$subcadena;
}
}

}
print "\nLa subcadena repetida más larga es: $subcadena";

Si me pueden ayudar con esto, se los agradecería mucho, no conozco las funciones de Perl, lo agarré hace unos días nada más y no conozco el lenguaje. Desde ya, muchas gracias.

Lo tengo casi resuelto, pero no anda bien la parte del buscar si se repite, con algunos ejemplos de cadenas no lo hace bien.

#!c:/perl/bin/perl.exe
open(CADENA,"C:/cadena.txt") || die "No se encuentra el archivo";
$linea=<CADENA>;
print $linea;
close(CADENA);
$subcadena="";
$aux="";
$e=-1;
@array=split("",$linea);
foreach $letra(@array){

$e++;
$i=$e;
for($e;$e<@array.length;$e++){
$subcadena .= "$array[$e]";
if($linea =~ /($subcadena){2,}/)
{
$res=1;
}
else{

$res=0;
}
if($res==1 && length($subcadena) > length($aux)){

$aux=$subcadena;
}
}
$e=$i;
$subcadena="";
}
print "\n$aux";
elesar
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2011-12-19 20:33 @898

Re: Ejercicio: encontrar la subcadena más larga

Notapor explorer » 2011-12-21 18:00 @791

La idea es buena, pero hay una serie de cuestiones que no están bien resueltas...
  • .length no existe en Perl. Quítalo
  • La expresión regular que usas para buscar cadenas utiliza el cuantificador {2,}, con lo que estás indicando que la $subcadena se debe repetir, al menos dos veces, seguidas, y decías que el problema era encontrar las repeticiones a lo largo de la $linea.
  • Podrías evitar el intercambio de valores en las variables $e e $i, si cada una de ellas tiene una misión clara
  • gt es para comparaciones alfanuméricas. Necesitas usar '>' para hacer comparaciones numéricas

Esta es mi versión, basada en la tuya:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. my $linea = '12345ja12345jaxd12345jaxd1117';
  7.  
  8. my $aux;
  9. my $aux_n = 0;
  10. my @array = split //, $linea;
  11.  
  12. for my $e (0 .. $#array) {                  # $e recorre los índices de todo el @array
  13.     my $subcadena = "";
  14.  
  15.     for (my $i = $e; $i < @array; $i++) {   # recorremos el resto de letras de la línea
  16.  
  17.         $subcadena .= $array[$i];           # subcadena a buscar
  18.  
  19. #        print "[$subcadena]:";
  20.        
  21.         my $pos = $e - 1;                   # damos un paso atrás, ya que luego sumamos 1
  22.         my $cnt = 0;                        # contador de apariciones
  23.  
  24.         while ($pos < @array) {                         # usamos index para buscar,
  25.             $pos = index($linea, $subcadena, $pos+1);   # a partir de la posición $pos+1
  26.             if ($pos != -1) {                           # la encontramos
  27.                 $cnt++;                                 # contamos una vez más
  28.             }
  29.             else {                                      # no encontramos más,
  30.                 last;                                   # terminamos
  31.             }
  32.         }
  33.  
  34. #        print "$cnt\n";
  35.  
  36.         # Valor más alto: si ha habido más de una repetición y
  37.         # la longitud es mayor de la encontrada hasta ahora
  38.         if ( $cnt > 1  and  length($subcadena) > length($aux) ) {
  39.             $aux   = $subcadena;
  40.             $aux_n = $cnt;
  41.         }
  42.     }
  43. }
  44.  
  45. print "[$aux][$aux_n]\n";               # informamos de la cadena y veces que aparece
  46.  
  47. __END__
  48. [12345jaxd1][2]
  49.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

Esta es otra versión, usando expresiones regulares, pero menos eficiente
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use 5.010;
  3. use strict;
  4. use warnings;
  5. use diagnostics;
  6.  
  7. my $linea = '12345ja12345jaxd12345jaxd1117';
  8. #say $linea;
  9.  
  10. my $aux;
  11.  
  12. $linea =~ /
  13.     (.+)                                        # buscamos una subcadena
  14.     .*?                                         # que está separado por unas letras
  15.     \1                                          # de una copia de sí misma (vamos, otra repetición)
  16.     (?{                                         # entonces, ejecutamos
  17.         if (length($1) > length($aux)) {        # si lo encontrado es mayor de lo que teníamos
  18.             $aux = $1;                          #   lo guardamos
  19.             #say "[$aux]";                      #   y pintamos (opcional)
  20.         }
  21.     })
  22.     (*FAIL)                                     # repite la búsqueda por toda la cadena
  23.     /x;
  24.  
  25. say $aux;                                       # pintamos la subcadena encontrada
  26.  
  27. __END__
  28. 12345jaxd
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


P.D. Como curiosidad, en la cadena de búsqueda, hay otra subcadena de la misma longitud que la encontrada antes: 2345jaxd1. Para encontrar ésta última, basta con cambiar los '>' por '>='.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ejercicio: encontrar la subcadena más larga

Notapor elesar » 2011-12-21 20:39 @902

Hola, muchas gracias , me sirvió la ayuda.
Te dejo cómo quedó el programa andando
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!c:/perl/bin/perl.exe
  2. open( CADENA, "C:/cadena.txt" ) || die "No se encuentra el archivo";
  3. $linea = <CADENA>;
  4. print $linea;
  5. close(CADENA);
  6. $subcadena = "";
  7. $aux       = "";
  8. @array     = split( "", $linea );
  9. for $e ( 0 .. $#array ) {
  10.     $subcadena = "";
  11.     for ( $i = $e; $i < @array . length; $i++ ) {
  12.         $subcadena .= "$array[$i]";
  13.         $posi = $e - 1;
  14.         $cont = 0;
  15.         while ( $posi < @array ) {
  16.             $posi = index( $linea, $subcadena, $posi + 1 );
  17.             if ( $posi != -1 ) {
  18.                 $cont++;
  19.             }
  20.             else {
  21.                 last;
  22.             }
  23.         }
  24.         if ( ( $cont > 1 ) && ( length($subcadena) > length($aux) ) ) {
  25.  
  26.             $aux = $subcadena;
  27.         }
  28.  
  29.     }
  30.  
  31. }
  32. print "\n$aux";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Así anda :D Muchas gracias.
Última edición por explorer el 2011-12-21 21:27 @935, editado 1 vez en total
Razón: Formateado de código con Perltidy y poner marcas Perl
elesar
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2011-12-19 20:33 @898

Re: Ejercicio: encontrar la subcadena más larga

Notapor explorer » 2011-12-21 21:33 @939

Cosas que debes corregir:

  • Si estás empezando con Perl, es muy aconsejable tener activados 'strict' y 'warnings', para que sea Perl quien te ayude a programar
  • El '||' en el open() no es aconsejable ponerlo, pues puede dar problemas en el futuro. Mejor usar 'or'
  • El 'length' de la línea 11 NO forma parte del lenguaje, así que se trata de un error. Perl no te ha avisado porque no tienes activos los 'warnings'. Ya te dije que lo quitaras
  • Las comillas de la línea 12, sobran
  • El montón de paréntesis que has puesto en la línea 24 es porque usas '&&' en lugar de 'and'. Compara con mi código

Esta es otra versión, un poco más optimizada
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use 5.010;
  3. use strict;
  4. use warnings;
  5. use diagnostics;
  6.  
  7. my $linea = '12345ja12345jaxd12345jaxd1117';
  8. #my $linea = 'abcdefghijklmnopqrstuvwxyz088';            # caso extremo
  9.  
  10. my $l     = length $linea;
  11. my $aux   = '';
  12.  
  13. for my $e (0 .. $l-2) {                                 # recorremos desde el principio hasta el penúltimo
  14.  
  15.     my $maxima = ($l - $e) / 2;                         # longitud de la repetición máxima que podemos encontrar
  16.  
  17.     for my $i (1 .. $maxima) {                          # recorremos el resto de letras de la línea
  18.         my $subcadena = substr $linea, $e, $i;          # subcadena a buscar
  19.  
  20.         my $pos = index $linea, $subcadena, $e+$i;      # buscamos a partir del final de la propia subcadena
  21.  
  22.         # Hemos encontrado una subcadena que se repite, mayor, si
  23.         # hemos encontrado (al menos) una repetición, y
  24.         # su longitud es mayor que el de la encontrada antes
  25.         if ( $pos != -1  and  $i > length $aux ) {
  26.             $aux   = $subcadena;                        # la recordaremos
  27.         }
  28.     }
  29. }
  30.  
  31. say $aux;                                               # informamos de la cadena que más se repite
  32.  
  33. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Ejercicio: encontrar la subcadena más larga

Notapor elesar » 2011-12-23 15:49 @700

Ok, muchas gracias por la ayuda. Saludos.
elesar
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2011-12-19 20:33 @898


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 47 invitados

cron