Página 1 de 1

Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-27 09:08 @422
por Vertik
Hola,

Tengo un script Perl que funciona correctamente en Linux y Windows. Este script hace un control de caracteres de un documento.

Pues en Solaris, pensé, ira igual de bien, pero, sorpresa para mi, no funciona igual de bien. Lo problemática es que el fichero solución lo crea en Latin1 cuando en los otros sistemas lo hace en utf8 (mismo código). ¿Qué puede ser? ¿Alguna idea?

Mil gracias.

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-27 09:47 @449
por explorer
Latin1 es la codificación por defecto que usará Perl, sino se le dice nada, a la hora de leer y escribir de los ficheros.

Perl es, actualmente, el mejor lenguaje de programación con soporte para las distintas codificaciones, y el mejor también para trabajar en UTF8. Pero para hacerlo bien, debes siempre de indicar en qué codificación quieres que trabaje.

use utf8; no es para trabajar con codificaciones. Ese pragma solo sirve para indicar que el propio código del programa está escrito en codificación utf8. No dice nada de qué hacer con los ficheros que se leen y se escriben ni las salidas a pantalla.

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-27 09:54 @454
por Vertik
¿Y cómo puede ser posible que en Windows y Linux use la codificación utf8 para crear los ficheros?

¿Es un suceso paranormal? T.T

Entonces votas/indicas que haga esto, ¿no?
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. open (filehandle,"<:utf8","$rutafichero");
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-27 12:22 @557
por explorer
Desconozco cómo son tus programas, así que no sé qué transformaciones haces.

Lo que sorprende a los programadores, es que, cuando pasan de un sistema a otro, o incluso en el mismo sistema hardware y le actualizan el sistema software, sus programas dejan de funcionar o funcionan mal. Y todo porque el sistema de codificación de caracteres ha cambiado o es distinto.

En ese momento se dan cuenta de que hasta ahora trataban a los ficheros como un flujo de bytes, no como un flujo de caracteres.

Tú siempre puedes tratar a un fichero como un flujo de bytes. Entonces lo abres, escribes en él, haces búsquedas, transformaciones, etc. Mientras no te metas con los caracteres tildados y "extraños", todo va bien. El problema aparece si un día necesitas buscar por un carácter tildado. Bueno, en principio lo resuelves poniendo 'use utf8;' en el programa, y de esa manera, Perl sabe que la 'ñ' que has puesto en tu programa, en lugar de ser un único byte 241 en codificación latin1, son dos bytes en codificación UTF8 (y contando que estés en un editor que trabaje en UTF8, también). Si luego sigues haciendo las operaciones anteriores con los ficheros, Perl usará esos dos bytes cada vez que quieras buscar/sustituir esa 'ñ'. Pero sigues trabajando en bytes.

A partir de Perl 5.8, se dio un impulso especial a todo el tema del tratamiento de ficheros y flujos de entrada y de salida, basada en caracteres. De hecho, Perl siempre trabaja, internamente, en caracteres Unicode, salvo que indiquemos que queremos trabajar en bytes. Por eso, es importantísimo, siempre, indicar en qué codificación vamos a leer qué fichero y en cuál vamos a escribir. Perl se encargará de hacer las transformaciones entre las codificaciones de caracteres.

Yo, desde hace mucho tiempo, trabajo en sistemas operativos con codificación UTF8. Y los editores de programas y texto y terminales de línea de comando, lo mismo (hace unos pocos años, era un lío: cada cosa tenía su propia codificación).

Para mis programas Perl, entonces, colocaba siempre estas líneas, al principio:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use Modern::Perl;      # Somos modernos
  3. use utf8;              # este programa está escrito en utf8
  4.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

El módulo Modern::Perl activa el 'strict', el 'warning' y las nuevas 'features' de Perl v5.10. Y el 'utf8' indica que voy a usar esa codificación en el resto del programa.

Hoy en día uso una combinación mejor:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use common::sense;         # Hay que tener sentido común
  3. use open qw(:utf8 :std);   # la salida y la entrada estándar serán en utf8
  4. use autodie;               # es mejor morir que regresar con deshonor (proverbio Klingon)
  5.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

El módulo common::sense hace lo mismo que el Modern::Perl, pero además activa el utf8, y convierte algunos warnings en errores (que es lo que prefiero: que el programa falle si ocurre algo extraño).

Lo importante es lo que sigue: con el pragma open estoy indicando que, por defecto, todos los ficheros que voy a abrir estarán en codificación utf8. Y eso incluye a STDIN, STDOUT, STDERR (con el ':std').

Ejemplo.

Supongamos que estemos en un sistema y terminal con codificación UTF8. Hacemos las siguientes pruebas:

explorer@casa:~> perl -le 'print "á"'
á


Bueno, nada sorprendente, ¿no? le decimos a Perl que saque 'á' y eso hace.

explorer@casa:~> perl -le 'use utf8; print "á"'


¡Oops! ¿Qué pasa? Ahora hemos indicado que nuestro programa está escrito en UTF8, pero no sale nuestra letra. Y debería, porque estamos en una terminal con esa codificación.

explorer@casa:~> perl -le 'use utf8; print "á"' |hexdump -C
00000000 e1 0a |..|
00000002


Perl está emitiendo un 'á' pero en codificación latin1 (un byte 241). Claro: esa es la codificación por defecto en Perl.

explorer@casa:~> perl -le 'print "á"'|hexdump -C
00000000 c3 a1 0a |...|
00000003


Y ahora ya está todo más claro: si no decimos nada, al poner 'á' en el programa, Perl no ve una 'a', sino que solo ve dos bytes (0xc3 y 0xa1), y al sacarlos por la pantalla, es el propio terminal nuestro el que traduce esos dos bytes a uno solo.

Al poner el 'use utf8;', Perl ahora ya sabe que esos dos bytes, en realidad, equivalen a un solo carácter (¡Ojo! hay que prestar atención a las palabras: 'byte' != 'carácter') Perl, entonces, transforma esos dos bytes a un único carácter Unicode, de forma interna.

Y a la hora de salida, Perl sabe que tiene que sacar los caracteres en codificación latin1 (la de defecto), así que el carácter 'á', en Unicode, se transforma en una 'á' en latin1 (un byte 241).

Entonces... no nos vale solo con decir que el programa contiene caracteres UTF8, sino que queremos que la salida también sea en esa codificación.

explorer@casa:~> perl -le 'use utf8; use open qw(:utf8 :std); print "á"'
á
explorer@casa:~> perl -le 'use utf8; use open qw(:utf8 :std); print "á"' |hexdump -C
00000000 c3 a1 0a |...|
00000003


Ahora, con la ayuda de open, Perl ya sabe que debe sacar los caracteres en UTF8, y eso es lo que hace.

Hoy, con los nuevos Perl, se puede poner de forma abreviada:

explorer@casa:~> perl -CSDL -E 'use utf8; say "á"'



Con la línea que pones, estás indicando en qué codificación vas a leer $rutafichero, lo cual es lo correcto. Y esto hay que hacerlo en todos los open(), o usar el pragma open para indicar las codificaciones por defecto para todos los open().

Más información perldoc open.

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-28 01:49 @117
por salva
¿Será que en Solaris tienes una versión de Perl más antigua?

El soporte de Unicode es uno de los puntos donde más ha mejorado Perl en las últimas versiones, corrigiéndose gran cantidad de bugs.

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-28 09:37 @442
por Vertik
Pregunta tonta... Si tengo un contador de caracteres/bytes (ando liado, lo siento) ¿puede ser que en Windows "\n" sea 2 y en Linux, 1? Es decir, si tenemos
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
hola\n
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

¿el contador en Windows sería al final de 6 y el de Linux 5?

Re: Duda de use utf8 en diferentes sistemas

NotaPublicado: 2011-10-28 09:43 @446
por explorer
Sí. Los finales de líneas, en Windows/MS-DOS, son dos caracteres: CR y LF. En Linux, es solo LF.