[Madrid-pm] Lo prometido es deuda: sobre los encodings

DervishD bugs en dervishd.net
Dom Nov 4 10:22:46 PST 2007


    Hola :)

Como le prometí a Salva y a Joaquín, os cuento con más detalle el asunto
de los encodings y "mkdir". El código "de verdad" es largo y las partes
problemáticas están un poco repartidas. Además no es muy relevante
porque el problema se puede reproducir en pocas líneas.

Os pido perdón por usar términos como "encoding", que no son apropiados,
porque probablemente lo correcto sería hablar de "charsets", pero como
he visto que es la terminología común en Perl, prefiero usarlos así. Voy
a llamar "encoding" al juego de caractéres y a su codificación, aunque
esto no sea estrictamente correcto.

Supongamos que tenemos un fichero que contiene las letras "ññ"
codificadas en utf8 (o sea, 0xc3 0xb1 0xc3 0xb1). Las leemos así:

    # Ignorad el código en sí, es sólo para ilustrar
    open FICHERO, '<:utf8', 'mifichero.txt';
    my $letters = <FICHERO>;

Como sabemos SEGURO que el fichero está codificado en utf8, usamos el
"<:utf8". Esto se puede hacer de muchas formas, simplemente he usado la
que primero se me ha ocurrido y que además no estorba si tenemos que
leer otros ficheros en otros encodings. En este momento, el escalar
"$letters" contiene dos letras eñe codificadas en el encoding INTERNO de
Perl. Por lo general, utf8, pero puede ser cualquiera y NO deberíamos
asumir cual.

Seguimos con nuestro programa:

    print "$letters\n";

Sencillo ¿verdad?. Bien, ejecutamos nuestro programa en un sistema en el
que el encoding de la terminal es utf8. Bien, imprime dos hermosas
letras ñ. Ahora lo ejecutamos en otro sistema en el que el encoding es
latin1 y TAMBIÉN imprime dos hermosas letras eñe. El intérprete de Perl
es lo bastante listo como para convertir automaticamente de su encoding
interno al encoding de la terminal. Guay :))))

¿Cuál es el problema, entonces? Añadamos otra línea a nuestro programa:

    mkdir $letters;

Ejecutamos el programa en un sistema en el que el encoding sea UTF8 y
funciona: crea un directório llamado "ññ", dos eñes. Qué listo es Perl
¿verdad? Pues no, esto funciona de casualidad, porque el encoding
interno de Perl es utf8. Si no, no funcionaría. La prueba es que si
ejecutamos nuestro script en un sistema latin1, crea un directório tal
que: ññ, o sea "Atilde" "plusminus" "Atilde" "plusminus". Cosas igual
de bizarras ocurren si el sistema es utf16, UCS2, UCS4, o cualquier otro
encoding. Por supuesto, si el sistema de ficheros limita el conjunto de
caractéres, ahí no hay más que rascar.

Resumiendo: la función "mkdir" (y otras) recibe una cadena en una
codificación y la usa tal cual, independientemente de cuál sea el
encoding del sistema.

La SOLUCIÓN es cambiar ese "mkdir" de arriba por el siguiente código:

    use I18N::Langinfo qw(langinfo CODESET);
    use Encode;

    mkdir encode(langinfo(CODESET), $letters);

Esto funciona y crea el directório como "ññ", codificadas ambas eñes con
el encoding que tenga el sistema. Si es utf8 como 0xc3 0xb1, si es
latin1 como 0xf1, etc. Ojo, no hagáis esto de arriba en casa: la
constante "CODESET" no tiene por qué estar definida en todos los
sistemas, así que hay que usar "eval" y demás. Podéis consultar la
página de manual de I18N::Langinfo para más información.

Hasta aquí el problema y su solución, que es basicamente lo mismo que
debe de hacer el intérprete para STDIN y STDOUT de forma automática. La
cuestión, que es lo que yo quería saber, es si hay una forma más
sencilla de hacer lo mismo, sin tener que usar "encode" por sistema, y
sin tener que usar "langinfo", algo que se haga de forma automática con
un pragma, etc. Además, podría haber algún sistema operativo estúpido
que usara un charset para entrada salida y otro para el sistema de
ficheros, con lo cual todo lo de arriba no habría servido para nada,
estaríamos usando un encoding incorrecto.

Fijáos que pragmas como "use utf8" sólo sirven para el propio código
fuente del script, otros como "use open IO..." sirven para la entrada y
salida pero NO a la hora de interactuar con el sistema de ficheros. Mi
pregunta es: ¿existe alguna forma de que la traducción automática de
encodings de Perl funcione también para las funciones que interactúan
con el sistema de ficheros (¡o con la red!)?

Muchas gracias y espero que ahora me haya explicado bien. La verdad es
que mi mensaje original daba un poco de pena... O:)

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736 | http://www.dervishd.net
It's my PC and I'll cry if I want to... RAmen!
We are waiting for 13 Feb 2009 23:31:30 +0000 ...


Más información sobre la lista de distribución Madrid-pm