• Publicidad

Soporte unicode

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

Soporte unicode

Notapor otronovato » 2013-08-26 16:16 @719

Un saludo a todos.

Estoy haciendo unos sencillos ejercicios de criptografía gracias a Perl y en los cifrados por sustitución me encuentro con el problema de los caracteres no ASCII.

He tanteado el problema del soporte a utf-8 en un script para establecer la frecuencia de los caracteres que aparecen en una cadena con cierto éxito. El código es el siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. #!/usr/bin/perl                                                                                                   
  2.  
  3. use strict; 
  4. use warnings; 
  5. use utf8; 
  6. use Encode; 
  7.  
  8.  
  9. my @mcifra = split '',decode('UTF-8',$ARGV[0]); 
  10. my %frecuencia; 
  11.  
  12.  
  13. foreach(@mcifra){ 
  14.   $frecuencia{$_}++; 
  15.  
  16. foreach my $clave (sort keys %frecuencia){ 
  17.  
  18.   print encode('UTF-8',$clave); 
  19.   print '*' x $frecuencia{$clave}; 
  20.   print "\t\t\t\t$frecuencia{$clave}\n"; 
  21.  


Pero no sé cómo meterle mano al script de cifrado César para que trabaje con la 'ñ', por ejemplo. Mi código es este:
Sintáxis: [ Descargar ] [ Ocultar ]
  1. #!/usr/bin/perl                                                                                                   
  2.  
  3. use strict; 
  4. use warnings; 
  5.  
  6.  
  7. my @cifrado; 
  8. my $desplazamiento; 
  9. my @alfabeto = split '', qw/ABCDEFGHIJKLMNOPQRSTUVWXYZ/; 
  10. my @codigo = (1..26); 
  11. my %numtoalf; 
  12. my %alftonum; 
  13. my @mensaje; 
  14. my $num; 
  15. my $index; 
  16.  
  17. if($#ARGV != 1){ 
  18.   print "Uso: ./cesar.pl mensaje desplazamiento\n\n"; 
  19.   exit 0; 
  20.  
  21. @numtoalf{@codigo}=@alfabeto; 
  22. @alftonum{@alfabeto}=@codigo; 
  23.  
  24. @cifrado = split '',$ARGV[0]; 
  25. $desplazamiento = $ARGV[1]; 
  26.  
  27. print @cifrado, "\n\n"; 
  28.  
  29. foreach(@cifrado){ 
  30.  
  31.  
  32.   $num = $alftonum{$_}; 
  33.  
  34.   $index = ($num + $desplazamiento)%26; 
  35.  
  36.   if(!$index){ 
  37.  
  38.     $index = $num; 
  39.  
  40.   } 
  41.  
  42.   print $_, "\t\t", $num, "\t\t", $index,"\t\t",$numtoalf{$index},"\n\n"; 
  43.  
  44.   push(@mensaje, $numtoalf{$index}); 
  45.  
  46. print @mensaje, "\n\n" 


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

Publicidad

Re: Soporte unicode

Notapor explorer » 2013-08-26 17:05 @754

El tema es que no contemplas la presencia de ningún carácter distinto de los que pones en el programa: de la 'A' a la 'Z' (en la línea del split, veintiséis letras), por eso luego falla la línea $alftonum{$_};, porque no existe correspondencia cuando llega la 'ñ'.

Debes, primero, definir cuál es el alfabeto que vas a usar, y luego, no admitir ningún mensaje que contenga caracteres que estén fuera de ese alfabeto.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Soporte unicode

Notapor otronovato » 2013-08-26 17:17 @762

Cierto, he dejado el alfabeto inglés precisamente porque al añadir caracteres como la 'ñ' la salida aparecía como un carácter no imprimible (en realidad salían dos caracteres no imprimibles, supongo que dos bytes por el carácter 'ñ', a no ser que hubiera más errores en el algoritmo). Entiendo de todos modos por tu respuesta, que debo usar el módulo Encode de manera similar a como hice en el primer script. ¿Correcto? ¿Podéis proponer algún tutorial con ejemplos resueltos?

P.D. Por cierto, el algoritmo del cifrado César que he puesto está mal. Éste que pongo ahora, creo, funciona correctamente.

Sintáxis: [ Descargar ] [ Ocultar ]
  1. #!/usr/bin/perl                                                                                                   
  2.  
  3. use strict; 
  4. use warnings; 
  5.  
  6.  
  7. my @cifrado; 
  8. my $desplazamiento; 
  9. my @alfabeto = split '', qw/ABCDEFGHIJKLMNOPQRSTUVWXYZ/; 
  10. my @codigo = (0..25); 
  11. my %numtoalf; 
  12. my %alftonum; 
  13. my @mensaje; 
  14. my $num; 
  15. my $index; 
  16.  
  17. if($#ARGV != 1){ 
  18.   print "Uso: ./cesar.pl mensaje desplazamiento\n\n"; 
  19.   exit 0; 
  20.  
  21. @numtoalf{@codigo}=@alfabeto; 
  22. @alftonum{@alfabeto}=@codigo; 
  23.  
  24. @cifrado = split '',$ARGV[0]; 
  25. $desplazamiento = $ARGV[1]; 
  26.  
  27. print @cifrado, "\n\n"; 
  28.  
  29. foreach(@cifrado){ 
  30.  
  31.  
  32.   $num = $alftonum{$_}; 
  33.  
  34.   $index = ($num + $desplazamiento)%26; 
  35.  
  36.  
  37.  
  38.   print $_, "\t\t", $num, "\t\t", $index,"\t\t",$numtoalf{$index},"\n\n"; 
  39.  
  40.   push(@mensaje, $numtoalf{$index}); 
  41.  
  42. print @mensaje, "\n\n" 
  43.  


(Está pensado, como podéis ver, para recibir una cadena de caracteres en mayúsculas sin espacios en blancos)
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Soporte unicode

Notapor explorer » 2013-08-26 17:58 @790

El módulo Encode te puede servir para codificar y decodificar lo que recibes o envías, según una determinada codificación, pero eso no te libra de fijar un alfabeto de trabajo.

Es decir: si tu alfabeto de trabajo son solo 26 letras, da igual que hagas el Encode o no lo hagas: no tienes una traslación de las letras que están fuera de ese alfabeto.

Hay una solución muy cómoda, para el caso de trabajar exclusivamente en Unicode: vamos leyendo letra por letra del mensaje (que hemos pasado a Unicode con la ayuda de Encode), por cada letra, simplemente le sumamos el desplazamiento (no necesitamos ningún hash) al valor que nos devuelve ord().

Se puede hacer en la línea de comandos, por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. $ perl -CAS -E '($des, $msg) = @ARGV; $out .= chr $des + ord $_ for split //, $msg; say "[$out]"; $org .= chr -$des + ord $_ for split //, $out; say "[$org]"'  10 'No conozco ventura mayor que leños ardiendo bajo el mar.'
  2. [Xy*myxymy*ox~|k*wky|*{o*voûy}*k|nsoxny*lkty*ov*wk|8]
  3. [No conozco ventura mayor que leños ardiendo bajo el mar.]
Coloreado en 0.003 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: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Soporte unicode

Notapor otronovato » 2013-08-26 19:21 @848

Esto es lo mejor que he conseguido por ahora al incorporar la 'Ñ'. Pero la salida no es correcta. Esta forma de trabajar con Unicode me parece verdaderamente muy dura.

Sintáxis: [ Descargar ] [ Ocultar ]
  1. #!/usr/bin/perl                                                                                                   
  2.  
  3. use strict; 
  4. use warnings; 
  5. use utf8; 
  6. use Encode; 
  7.  
  8. my @cifrado; 
  9. my $desplazamiento; 
  10. my @alfabeto = split '', decode('UTF-8',qw/ABCDEFGHIJKLMNÑOPQRSTUVWXYZ/); 
  11. my @codigo = (0..26); 
  12. my %numtoalf; 
  13. my %alftonum; 
  14. my @mensaje; 
  15. my $num; 
  16. my $index; 
  17.  
  18.  
  19. if($#ARGV != 1){ 
  20.   print "Uso: ./cesar.pl mensaje desplazamiento\n\n"; 
  21.   exit 0; 
  22.  
  23. @numtoalf{@codigo}=@alfabeto; 
  24. @alftonum{@alfabeto}=@codigo; 
  25.  
  26. @cifrado = split '',decode('UTF-8',$ARGV[0]); 
  27. $desplazamiento = $ARGV[1]; 
  28.  
  29. print encode('UTF-8', join('',@cifrado)), "\n\n"; 
  30.  
  31. foreach(@cifrado){ 
  32.  
  33.  
  34.   $num = $alftonum{decode('UTF-8',$_)}; 
  35.  
  36.   $index = ($num + $desplazamiento)%27; 
  37.  
  38.  
  39.  
  40.   print encode('UTF-8', $_), "\t\t", $num, "\t\t", $index,"\t\t",encode('UTF-8',$numtoalf{$index}),"\n\n"; 
  41.  
  42.   push(@mensaje, $numtoalf{$index}); 
  43.  
  44.  
  45. my $plano = join ('', @mensaje); 
  46. print encode('UTF-8',$plano), "\n\n"; 
  47.  
  48.  


Ejemplos de salida:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
xxxxx@xxxxx:~/Escritorio$ ./cesar_utf8.pl AÑODENIEVESAÑODEBIENES 2
AÑODENIEVESAÑODEBIENES

A               0               2               C

Ñ              14              16              P

O               15              17              Q

D               3               5               F

E               4               6               G

N               13              15              O

I               8               10              K

E               4               6               G

V               22              24              X

E               4               6               G

S               19              21              U

A               0               2               C

Ñ              14              16              P

O               15              17              Q

D               3               5               F

E               4               6               G

B               1               3               D

I               8               10              K

E               4               6               G

N               13              15              O

E               4               6               G

S               19              21              U

CPQFGOKGXGUCPQFGDKGOGU
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


No obstante al revertir el proceso, sigue sin salir correctamente.
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
xxxxx@xxxxx:~/Escritorio$ ./cesar_utf8.pl CPQFGOKGXGUCPQFGDKGOGU 25
CPQFGOKGXGUCPQFGDKGOGU

C               2               0               A

P               16              14              �

Q               17              15              O

F               5               3               D

G               6               4               E

O               15              13              N

K               10              8               I

G               6               4               E

X               24              22              V

G               6               4               E

U               21              19              S

C               2               0               A

P               16              14              �

Q               17              15              O

F               5               3               D

G               6               4               E

D               3               1               B

K               10              8               I

G               6               4               E

O               15              13              N

G               6               4               E

U               21              19              S

A�ODENIEVESA�ODEBIENES
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


P.D.: Gracias, explorer, por la elegante solución que propones al problema. Me temo que estoy a años luz de algo así. En cualquier caso, más que el problema del cifrado César en sí, lo que me interesaba es asomarme al problema del Unicode.
Última edición por explorer el 2013-08-27 11:05 @503, editado 1 vez en total
Razón: Poner marcas de texto
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Soporte unicode

Notapor explorer » 2013-08-27 11:27 @519

Con unos pequeños cambios, ya sale bien:
Sintáxis: (cesar_utf8.pl) [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.12;
  3. use strict;
  4. use warnings;
  5. use utf8;
  6. use Encode;
  7.  
  8. my @cifrado;
  9. my $desplazamiento;
  10. my @alfabeto = split //, 'ABCDEFGHIJKLMNÑOPQRSTUVWXYZ';
  11. my @codigo = ( 0 .. $#alfabeto );
  12. my %numtoalf;
  13. my %alftonum;
  14. my @mensaje;
  15. my $num;
  16. my $index;
  17.  
  18. binmode STDOUT, ":utf8";               # la salida en pantalla es en utf8
  19.  
  20. if ( $#ARGV != 1 ) {
  21.     print "Uso: ./cesar.pl mensaje desplazamiento\n\n";
  22.     exit 0;
  23. }
  24.  
  25. @numtoalf{@codigo}   = @alfabeto;
  26. @alftonum{@alfabeto} = @codigo;
  27.  
  28. @cifrado = split //, decode( 'UTF-8', $ARGV[0] );    # el argumento estará en utf8, asi que necesitamos decodificarlo
  29.  
  30. $desplazamiento = $ARGV[1];
  31.  
  32. print join( '', @cifrado ), "\n\n";
  33.  
  34. foreach (@cifrado) {
  35.  
  36.     $num = $alftonum{$_} // warn "ERROR: No tenemos definido cambio para carácter [$_]";
  37.  
  38.     $index = ( $num + $desplazamiento ) % @codigo;
  39.  
  40.     print $_, "\t\t", $num, "\t=>\t", $index, "\t\t", $numtoalf{$index}, "\n\n";
  41.  
  42.     push( @mensaje, $numtoalf{$index} );
  43.  
  44. }
  45.  
  46. my $plano = join( '', @mensaje );
  47.  
  48. print $plano, "\n\n";
Coloreado en 0.004 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: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Soporte unicode

Notapor otronovato » 2013-08-27 13:05 @587

¡Gracias!

Anoche me pegué un rato peleándome con Encode. Sabía que no podía ser tan complicado como lo estaba haciendo. Hasta la fecha no había utilizado binmode más que para establecer el modo binario cuando accedo a archivos. No se me ocurrió aplicarlo al problema que tenía con stdout.

Sabía que al utilizar un array en contexto escalar te daba como resultado su longitud, pero nunca lo había utilizado.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $index = ( $num + $desplazamiento ) % @codigo;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Lo cierto es que es muy cómodo. Más robusto que dejar el valor "hardcoded" (¿se dice así?) en el código fuente y menos engorroso que ($#codigo + 1).

El uso de warn también me ha gustado. Habitualmente hubiera utilizado eval() para capturar errores, o die en casos como apertura de ficheros, etc. Precisamente acabo de comprar "Perl sin errores" de Martin Brown para ver si me entero un poco de cómo darle robustez al código. ¿Es un buen libro?.

En cuanto al código que proponías ayer:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. ($des, $msg) = @ARGV;
  2. $out .= chr $des + ord $_ for split //, $msg;
  3. say "[$out]";
  4. $org .= chr -$des + ord $_ for split //, $out;
  5. say "[$org]"'  10 'No conozco ventura mayor que leños ardiendo bajo el mar.'
  6.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


De las pocas veces que he tenido que trabajar con objetos en Perl me ha quedado la costumbre de utilizar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $msg = pop @ARGV;
  2. $des = pop @ARGV;
  3.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Entiendo que usando la lista de escalares, sigo conservando los parámetros en @ARGV. Usar la lista de escalares parece mucho más sencillo. ¿Puedo generalizar su uso en este contexto? Entiendo que es casi como trabajar con un hash introduciendo las claves "a mano".

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $out .= chr $des + ord $_ for split //, $msg;
  2.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Esta sentencia me sorprendió bastante. No había usado nunca el bucle for de esta manera, equivalente a un foreach. De hecho me lío bastante con la sintaxis de algunas sentencias y funciones que a veces reciben los argumentos entre paréntesis y otras veces sin ellos. ¿Algún consejo?

Entiendo que $out recibe la concatenación de los caracteres resultado de la suma explícita de caracteres ('A' + 'B') por ejemplo, que supongo que se resuelve como el carácter resultado de sumar los códigos ASCII de 'A' y 'B', con lo que si es mayor de 127, ( o 255), tendremos un carácter no imprimible. ¿Usar Encode y establecer binmode STDOUT ":utf8" solucionaría el problema en general?

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

Re: Soporte unicode

Notapor explorer » 2013-08-27 16:07 @713

otronovato escribiste:Precisamente acabo de comprar "Perl sin errores" de Martin Brown para ver si me entero un poco de cómo darle robustez al código. ¿Es un buen libro?
Pues... no lo conozco... Tendrás que leerlo y luego hacernos una reseña :)

otronovato escribiste:Entiendo que usando la lista de escalares, sigo conservando los parámetros en @ARGV. Usar la lista de escalares parece mucho más sencillo. ¿Puedo generalizar su uso en este contexto? Entiendo que es casi como trabajar con un hash introduciendo las claves "a mano".
Humm... pues... depende de cada situación... Yo creo que lo que más he visto por ahí es, primero, comprobar que el número de argumentos es el esperado, y luego, si el número de argumentos es pequeño, usar shift(); y asignación a una lista, en caso de ser más numerosos. Pero hay de todo. Por ejemplo, te puede interesar no modificar @ARGV, si luego lo usas más veces a lo largo del programa.

otronovato escribiste:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $out .= chr $des + ord $_ for split //, $msg;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Esta sentencia me sorprendió bastante. No había usado nunca el bucle for de esta manera, equivalente a un foreach. De hecho me lío bastante con la sintaxis de algunas sentencias y funciones que a veces reciben los argumentos entre paréntesis y otras veces sin ellos. ¿Algún consejo?
En Perl se pueden quitar la mayor parte de los paréntesis de las funciones incorporadas, siempre y cuando sepamos que la precedencia de la ejecución va a ser correcta. En este caso, no hace faltan los paréntesis alrededor de la suma, porque ésta se realiza antes. ¡Pero...! quedaría más clara la operación si sí pusiéramos los paréntesis. (No te creas que yo sabía de principio si se podían quitar o no los paréntesis ;) Lo normal es empezar por ponerles todos, y cuando todo funciona, empezar a quitarlos :D ).

otronovato escribiste:Entiendo que $out recibe la concatenación de los caracteres resultado de la suma explícita de caracteres ('A' + 'B') por ejemplo, que supongo que se resuelve como el carácter resultado de sumar los códigos ASCII de 'A' y 'B', con lo que si es mayor de 127, ( o 255), tendremos un carácter no imprimible. ¿Usar Encode y establecer binmode STDOUT ":utf8" solucionaría el problema en general?
A ver... se trata de un compromiso entre hacer un programa corto, y que al menos funcione bien en la "mayor" parte de los casos.

Lo que hace el programa, primero, es sacar el número de orden (ord()) del carácter que estamos procesando. Como el mensaje está codificado en utf8, sé que voy a obtener un número entre 0 y cuatro mil millones. Por ejemplo, en caso de tener el carácter que representa a la torre de negras del ajedrez:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
> perl -E 'use utf8; say ord "♜"'
9820
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Bueno, una vez que tengo ese número (oficialmente se llama punto de código), le sumamos el desplazamiento, obteniendo otro punto de código. Solo queda pasárselo a chr() para obtener el carácter correspondiente.

Todo esto lo hago sin mirar los límites de los números, porque, supongo, será muy difícil que el usuario me dé un desplazamiento tan grande como para que me salga del rango Unicode. (Con un desplazamiento 848 nuestro mensaje sale en griego ;) )

En cuanto a las preguntas de Encode y binmode. Encode sirve para pasar de una codificación a otra, en caso de que recibamos información de fuera o queramos guardarla en otra.

Lo que hace binmode(), internamente, es muy parecido al Encode, pero referido a los archivos. Quiere decir que tomará los caracteres que Perl tiene (que pueden estar en Unicode o en iso-8859-1 (latin1)), y los "pasa" a la codificación deseada en la salida. O los traduce en caso de leerles.

En mi versión de tu programa, ves que he necesitado usar Encode para codificar el argumento de entrada. No he necesitado codificar la 'Ñ' del código, porque para eso ya está el 'use utf8;'. Con eso, ya tenemos variables escalares que en su interior no almacenan bytes, sino caracteres Unicode. Ya solo queda indicar, a la salida, cómo queremos que salgan esos caracteres, y para eso usamos el binmode.

Esta es otra versión:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use utf8::all;          # activa TODO el soporte para utf8. Realmente todo.
  4.  
  5. @ARGV == 2  or  die "Uso: $0 <mensaje> <desplazamiento>\n";
  6.  
  7. my($mensaje, $desplazamiento) = @ARGV;
  8.  
  9. exit if not $mensaje or not $desplazamiento;
  10.  
  11. my @alfabeto = ('A' .. 'Z', 'Ñ', 'Á', 'É', 'Í', 'Ó', 'Ú', 'Ç', 'Ü');
  12.  
  13. my %alfa_a_num = map { $alfabeto[$_] => $_ } 0 .. $#alfabeto;
  14.  
  15. for my $char (split //, $mensaje) {
  16.  
  17.     if (not exists $alfa_a_num{ $char }) {
  18.         warn "ATENCIÓN: No sabemos codificar el carácter [$char]\n";
  19.         next;
  20.     }
  21.  
  22.     print
  23.         $alfabeto[
  24.             ( $alfa_a_num{$char} + $desplazamiento )    # extraemos el código, y lo desplazamos
  25.             % @alfabeto                                 # pero dentro de los límites del alfabeto
  26.         ]                                               # y lo usamos como índice para sacar el nuevo carácter
  27.         ;                                               # y lo imprimimos
  28. }
  29.  
  30. print "\n";
Coloreado en 0.003 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: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Soporte unicode

Notapor otronovato » 2013-08-28 03:33 @190

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use utf8::all
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
¡Un módulo verdaderamente magnífico! Lo malo de la literatura sobre Perl, al menos la que he consultado, es que asume por defecto las reducidas necesidades del programador novato de habla inglesa. Es una pena que se introduzcan sistemáticamente en esas obras módulos altamente especializados como el CGI y que otros, como el que nos ocupa, que cubren necesidades básicas, sean dejados de lado. (También pudiera ser que mi selección de lecturas haya sido defectuosa, claro).

En cualquier caso, tras instalarme medio CPAN, eso sí, tengo una herramienta que soluciona mis problemas de un plumazo. Si además, como espero, las expresiones regulares funcionan correctamente con este módulo... ¡Me tocará re-escribir mucho código!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my @alfabeto = ('A' .. 'Z', 'Ñ', 'Á', 'É', 'Í', 'Ó', 'Ú', 'Ç', 'Ü');
  2.  
  3. my %alfa_a_num = map { $alfabeto[$_] => $_ } 0 .. $#alfabeto;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Recuerdo haber leído algún ejemplo de construcción de hashes mediante map en "Intermediate Perl", y de hecho, alguna vez lo uso, aunque no me sale de modo "natural". Me temo que programo Perl como Salvatore, el de "El nombre de la Rosa", hablaba latín: "con frases prestadas". Alucinante la flexibilidad de Perl.

P.D.: En unos días acabaré una primera lectura de "Perl sin errores", (digerir lo que sea capaz de digerir me costará meses), y haré una pequeña reseña. De momento me parece un libro muy prometedor, aunque para aprovecharlo como merece necesitaría un nivel de conocimiento muy superior al mío.
otronovato
Perlero nuevo
Perlero nuevo
 
Mensajes: 44
Registrado: 2013-08-26 06:12 @300

Re: Soporte unicode

Notapor explorer » 2013-08-28 06:26 @310

Bueno, CPAN está lleno de pequeñas joyas... lo que hay que hacer es estar atento a las novedades o, lo más normal, leer código que hacen otros programadores.

También te encontrarás con puristas del lenguaje y jefes de desarrollo que no quieren oír hablar de nuevos módulos, porque eso implica que tu programa tiene más 'dependencias' del exterior, y eso implica un trabajo extra para mantenerlo (¡Como si los programadores de Java fueran capaces de vivir sin sus bibliotecas externas! ;) ).

En última instancia, el código está disponible, así que podríamos mirar qué es lo que hace utf8::all, y quedarnos con aquella parte del código que realmente nos interesa.

Lo importante es entender qué hace ese módulo en este programa, el porqué lo estamos usando.
  • decodifica los argumentos (@ARGV) en utf8
  • las entradas y salidas de archivos, serán también en esa codificación (use open qw(:utf8 :std))
  • incluso el código fuente contendrá caracteres así (use utf8)
Así que nos hemos ahorrado unas pocas líneas.

Tema interesante: los anglosajones no necesitan de la codificación utf8, o al menos no la han necesitado durante años, ya que la informática está dictada por ellos. Perl es un ejemplo de ello: si no dices nada, usará siempre la codificación por defecto iso-8859-1, que es la del alfabeto occidental. Por eso vemos cantidad de códigos que luego queremos hacer funcionar en nuestras máquinas y sí, funcionan, pero nos encontramos con problemas que son específicos de nuestro alfabeto (los caracteres tildados). Los programadores novatos escribirán cosas como esta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. print "La solución es: \n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
y se encuentran con que no ven la 'ó' en la pantalla, sino unos caracteres extraños. Y por no romperse la cabeza, deciden que lo más cómodo es quitar todos los caracteres tildados del código fuente. Se hubiera arreglado con un par de líneas, como ya hemos visto, indicando que la codificación usada era iso-8859-15 (la occidental, más el €uro).

Desde hace unos años, todos los sistemas ya están funcionando en utf8, así que ha cobrado importancia también entre los anglosajones, y Perl se ha convertido en el lenguaje con mejor soporte de utf8.

Si vemos ahora código de los anglosajones, veremos que ellos usan el utf8 cuando ya no les queda más remedio (hablar con una base de datos, por ejemplo). En cambio, nosotros, estamos obligados a usarlo siempre, ya que a) nuestras terminales funcionarán con esa codificación
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. $ echo $LANG
  2. es_ES.UTF-8
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
y b) necesitamos usar caracteres tildados cada dos por tres (print "Solución").

La ventaja es que, además, podemos usar esos caracteres tildados para los nombres de las variables:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my($solución, $es_fácil, @cañones);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Algunos recomiendan no hacerlo, pero, si hablamos de un programa que es para "consumo interno" nuestro, yo lo encuentro de lo más normal del mundo (y si no, basta con mirar algún código Perl en japonés :) )

En cuanto a lo de los hash, estoy completamente de acuerdo contigo: es una línea algo complicada, y ni siquiera a mi me resulta natural. Hubiera preferido hacer
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %alfa_a_num;
  2. for my $i (0 .. $#alfabeto) {                    
  3.     $alfa_a_num{$alfabeto[$i]} = $i;
  4. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
que es mucho más claro. O incluso un
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $alfa_a_num{$alfabeto[$_]} = $_ for 0 .. $#alfabeto;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
O como lo tenías hecho tú:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. @alfa_a_num{@alfabeto} = 0 .. $#alfabeto;
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: 14486
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: No hay usuarios registrados visitando el Foro y 0 invitados