• Publicidad

Guardando arrays en un hash (SOLUCIONADO)

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

Guardando arrays en un hash (SOLUCIONADO)

Notapor otronovato » 2013-09-01 07:16 @344

SOLUCIONADO

He escrito una función con la intención de que a partir de una referencia a un hash con los trigramas como claves y su número de apariciones en una cadena como valores, y de una cadena de la que se ha calculado ese hash mediante otra función, me almacene en un hash los trigramas repetidos y los lugares de la cadena en que aparecen.

Pero no funciona. Ni a tiros. :roll:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub análisis_frec{
  2.  
  3. #Recibe una referencia a un hash que contiene las cadenas (digramas o trigramas)
  4. #relacionadas con sus repeticiones, y una cadena con el mensaje cifrado.
  5. #Retorna un hash que relaciona cada cadena, (digrama o trigrama), con
  6. #la distancia en caracteres entre cada repetición.
  7.     my %dist;
  8.     my @dist_por_elemento;
  9.     my %input = %{$_[0]}; #Dereferencio el hash recibido
  10.  
  11.     foreach(sort keys %input){
  12.  
  13.         #print "Clave ",        $_, " valor ", $input{$_}, "\n";
  14.  
  15.         if($input{$_} > 1){ #Dejamos sin procesar los elementos que no aparecen repetidos
  16.  
  17.             my $offset = 0; #Es el offset que pasaré a index()
  18.             my $distancia;
  19.  
  20.             for(my $i = 0; $i < $input{$_}; $i++){ #Para cada una de las veces que aparece cada trigrama
  21.  
  22.                 $distancia = index $_[1], $_, $offset;#$_[1] almacena la cadena con el mensaje
  23.                 #EDIT ¡Barbaridad! $dist_por_elemento[$i]= $distancia;
  24.                 push @dist_por_elemento, $distancia;
  25.                 #EDIT ¡Vergonzoso! $offset += 2; #¿No puedo usar length porque estoy trabajando con caracteres no ascii??
  26.                 $offset = $distancia + 2;
  27.                 #print "Longitud ", $offset, "\n";
  28.             }
  29.  
  30.             #print "debug ",(split ',', @dist_por_elemento), "\n";
  31.             $dist{$_} = [@dist_por_elemento]; #AQUÍ ESTABA EL PROBLEMA: tenía $dist{$_} = @dist_por_elemento;
  32.             undef @dist_por_elemento;
  33.  
  34.         }
  35.  
  36.  
  37.     }
  38.  
  39.     return \%dist;
  40.  
  41. }
  42.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


EDITADO [Aparentemente calcula bien los desplazamientos, pero no los guarda en el array que deseo convertir en valor de cada clave del hash que retorna la función]. No era ese el problema.

Además tengo la duda de si con el módulo utf8::all funciona correctamente la función length(). Aquí me ha dado problemas, pero podrían haberse debido a la "creatividad" con que acometo el trabajo con hashes en estos momentos... :oops:

Un saludo.

EDITO[PS: He visto un montón de errores de lógica, y de aún sentido común, en el código que ya he editado. Aun con todo, no consigo ver por qué no funciona
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. push @dist_por_elemento, $distancia;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
] Solucionado.
PS: No hay como pensar. :oops:
Última edición por explorer el 2013-09-01 11:31 @521, editado 3 veces en total
Razón: Quitar espacios en blanco sobrantes, en los comentarios.
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Publicidad

Re: Guardando arrays en un hash (SOLUCIONADO)

Notapor explorer » 2013-09-01 11:21 @515

Mete la línea

my @dist_por_elemento;

dentro del if(), y quita la línea del undef, porque ya no hará falta. El my() creará un nuevo array, en cada vuelta.

Cuando haces la asignación [ @dist_por_elemento ], estás guardando una referencia a una lista de caracteres, que son los que había en ese array, así que es correcto (es un hash de arrays).

Cuando funcione, pruébalo con este caso, con una cadena así: 'AAAAAAAACCCCCCCG'

Cuidado, porque hay truco. :mrgreen:
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: Guardando arrays en un hash (SOLUCIONADO)

Notapor otronovato » 2013-09-01 12:15 @552

:roll: ¡Vaya día que llevo! ¡Tener problemas con Perl es una cosa, pero tenerlos con la lógica...! :lol:

Comprendido lo de la declaración de @dist_por_elemento. Como su alcance se limita al bloque en que ha sido declarada no necesito hacerla global a la función ni reiniciarla explícitamente.

Cuando funcione, pruébalo con este caso, con una cadena así: 'AAAAAAAACCCCCCCG'


Creo que ya lo tengo...

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $offset = $distancia + 3;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y la salida ahora queda:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. xxxx@xxxxxxx:~/Escritorio/scripts_criptografía$ ./frec_calc.pl 
  2. Introduce la cadena a considerar 
  3. AAAAAAAACCCCCCCG 
  4.  
  5. Hay 5 tríos de caracteres, que son AAA,AAC,ACC,CCC,CCG, 
  6.  
  7. La frecuencia de cada trigrama es: 
  8. Trigrama AAA    ------>2 
  9. Trigrama AAC    ------>1 
  10. Trigrama ACC    ------>1 
  11. Trigrama CCC    ------>2 
  12. Trigrama CCG    ------>1 
  13.  
  14. La DISTANCIA para AAA es 0 
  15. Empujo 0 dentro de @dist_por_elemento 
  16. La DISTANCIA para AAA es 3 
  17. Empujo 3 dentro de @dist_por_elemento 
  18. OFFSET----->0 
  19. OFFSET----->3 
  20. La DISTANCIA para CCC es 8 
  21. Empujo 8 dentro de @dist_por_elemento 
  22. La DISTANCIA para CCC es 11 
  23. Empujo 11 dentro de @dist_por_elemento 
  24. OFFSET----->8 
  25. OFFSET----->11 
  26. El trigrama AAA se encuentra en los desplazamientos 0,3, 
  27. El trigrama CCC se encuentra en los desplazamientos 8,11, 


¿Trampas? ¡Para mí una simple raya de lápiz en el suelo ya es una trampa! :lol:

Gracias, explorer.
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Guardando arrays en un hash (SOLUCIONADO)

Notapor explorer » 2013-09-01 12:50 @576

¿Estás completamente seguro de que en la cadena 'AAAAAAAACCCCCCCG' solo hay 2 trigramas 'AAA'? Yo veo más... Quizás, seis.
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: Guardando arrays en un hash (SOLUCIONADO)

Notapor otronovato » 2013-09-01 13:06 @588

¡Miér...coles! :roll:

Bueno... Por lo menos el programa falla porque no tengo claro lo que pretendía hacer, no por estar mal programado...
Vuelta a la casilla de salida, o casi.
¡Gracias!
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Guardando arrays en un hash (SOLUCIONADO)

Notapor otronovato » 2013-09-01 17:19 @763

Bueno... La función que hace el recuento no he tenido que tocarla. En cambio, la que calcula la frecuencia la he tenido que rehacer de arriba a abajo. De ser una cosa sencilla y limpia tal que así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub frecuencia{
  2. #Recibe una referencia a un array de cadenas de caracteres sin repetir y una cadena con
  3. #el mensaje. Devuelve una referencia a un hash con las frecuencias.
  4.     my %frec; #Estructura a retornar
  5.     %frec = map{$_,0}@{$_[0]};#Iniciamos el hash con los valores a distribuir
  6.     foreach(keys %frec){
  7.         my @control;
  8.         @control=$_[1] =~m/$_/g;
  9.         $frec{$_}=@control;
  10.     }
  11.     return \%frec;
  12. }
  13.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


A este monstruo de tenebroso aspecto:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub frecuencia{
  2. #Recibe una referencia a un array de cadenas de caracteres sin repetir y una cadena con                                                                                                                          
  3. #el mensaje. Devuelve una referencia a un hash con las frecuencias.                                                                                                                                              
  4. #Esta misma función nos puede dar las posiciones, pero para esa tarea he                                                                                                                                          
  5. #desarrollado otra subrutina. En resumidas cuentas, que estoy hoy perezoso para cambios                                                                                                                                                                                    
  6.     my %frec; #Estructura a retornar                                                                                                                                                                              
  7.     %frec = map{$_,0}@{$_[0]};#Iniciamos el hash con los valores a distribuir                                                                                                                                    
  8.     foreach(sort keys %frec){
  9.         my $pos_ant = -1;#inicio al valor de index() "no encontrado"                                                                                                                                              
  10.         my $offset = 0;
  11.         my @posiciones;
  12.         for(my $ind = 0; $ind < length $_[1]; $ind++){
  13.             my $pos = index $_[1], $_, $ind;                                                                                                                  
  14.             if(($pos >= 0) && ($pos_ant != $pos)){
  15.                 push @posiciones, $pos;
  16.             }
  17.             $pos_ant = $pos;
  18.         }
  19.         $frec{$_} = scalar @posiciones; #En contexto escalar me da la longitud del array control                                                                                                                  
  20.         undef @posiciones;
  21.     }
  22.     return \%frec;
  23. }
  24.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


El resultado, ahora:
xxxxx@xxxxx:~/Escritorio/scripts_criptografía$ ./frec_calc.pl
Introduce la cadena a considerar
AAAAAAAACCCCCCCG
Hay 5 tríos de caracteres, que son AAA,AAC,ACC,CCC,CCG,
La frecuencia de cada trigrama es:
Trigrama AAA ------>6
Trigrama AAC ------>1
Trigrama ACC ------>1
Trigrama CCC ------>5
Trigrama CCG ------>1
El trigrama AAA se encuentra en los desplazamientos 0,1,2,3,4,5,
El trigrama CCC se encuentra en los desplazamientos 8,9,10,11,12,


¿No habría una forma de hacer lo mismo mediante el operador match, como había hecho en la versión antigua? ¿Ningún modificador mágico?

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. @control=$_[1] =~m/$_/g;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¡Ayyyy, qué cabeza! :?
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Guardando arrays en un hash (SOLUCIONADO)

Notapor explorer » 2013-09-01 18:57 @831

Claro que se puede hacer con el operador de coincidencia.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.16;
  3. use utf8::all;                  # Turn on UTF-8. All of it.
  4.  
  5. my $cadena = 'AAAAAAAACCCCCCCG';
  6. my $trío   = 'AAA';
  7. my $veces;
  8.  
  9. while ( $cadena =~ /$trío/g) {
  10.     $veces++;
  11.  
  12.     # pos() devuelve la posición SIGUIENTE a donde se encontró el patrón
  13.     # por eso restamos 3, para saber la posición real
  14.     say "Encontrado en ", pos($cadena) - 3;
  15.  
  16.     # reposicionamos el puntero, para que busque en el carácter SIGUIENTE al primero,
  17.     # no queremos que busque desde el final del patrón anterior
  18.     pos($cadena) = pos($cadena) - 2;
  19. }
  20.  
  21. say "Encontrado $veces veces";
  22.  
  23. __END__
  24. Encontrado en 0
  25. Encontrado en 1
  26. Encontrado en 2
  27. Encontrado en 3
  28. Encontrado en 4
  29. Encontrado en 5
  30. Encontrado 6 veces
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
De hecho, esto mismo se hace para el caso de usar index(): modificas el $offset para indicar a partir de dónde quieres reiniciar la búsqueda.
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: Guardando arrays en un hash (SOLUCIONADO)

Notapor otronovato » 2013-09-02 07:04 @336

"pos" directly accesses the location used by the regexp engine to store the offset, so assigning to "pos" will change that offset

Entiendo que es una especie de función C fseek() pero para el motor de expresiones regulares y que se puede utilizar de manera similar.

De todos modos esta forma de trabajar precisaría de otro bucle para pasar las cadenas de búsqueda, que además habría que determinar en una función previa, por lo que parece, a simple vista, una mala opción. ¿Correcto? (A no ser, claro, que lo que tuviera que buscar fueran expresiones regulares predeterminadas...)

PS: estaba pensando en la manera de detectar bucles que usó Turing para romper Enigma: http://fr.wikipedia.org/wiki/Cryptanalyse_d'Enigma. ¿Cómo de grandes pueden ser las expresiones regulares?

Un saludo
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Guardando arrays en un hash (SOLUCIONADO)

Notapor explorer » 2013-09-02 11:20 @514

otronovato escribiste:¿Cómo de grandes pueden ser las expresiones regulares?
El límite es la memoria RAM.

Por ejemplo, en el libro "Mastering Regular Expressions" (séptima edición, diciembre 1998, página 316), aparece una monstruosa exp. reg. de 6598 bytes de longitud, para verificar si una dirección de correo electrónico está correctamente escrita, o no.

:lol:
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


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: Bing [Bot] y 11 invitados