Códigos de caracteres en R

Esta entrada acompaña y remata para los usuarios de R la que escribí en general sobre los códigos de caracteres. Es un pequeño experimento en el que comparo lo que pasa al leer un fichero de texto codificado de dos maneras distintas en dos plataformas, Linux y Windows, que usan códigos de caracteres distintos.

Primero creo dos ficheros (en Linux) con el mismo contenido pero codificados de dos maneras distintas, utf-8 y latin1:

1
2
3
4
5
6
$ echo "hóla;adiós" > hola_utf8.txt
$ file hola_utf8.txt
hola_utf8.txt: UTF-8 Unicode text
$ iconv -f utf-8 -t latin1 hola_utf8.txt > hola_latin1.txt
$ file hola_latin1.txt
hola_latin1.txt: ISO-8859 text

Los ficheros pueden descargarse de este enlace.

La codificación interna de caracteres en Linux (al menos, en el mío) es utf-8. En Windows no lo tengo tan claro, pero parece que es algo similar a latin1.

Mi experimento consiste en ejecutar tanto en Linux como en Windows el siguiente código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
foo <- function( file, encoding ){
    a <- scan( file, what = "character",
                fileEncoding = encoding )
    strsplit( a, ";" )
}

foo( "hola_latin1.txt", "latin1" )
foo( "hola_latin1.txt", "utf-8" )
foo( "hola_latin1.txt", "" )

foo( "hola_utf8.txt", "latin1" )
foo( "hola_utf8.txt", "utf-8" )
foo( "hola_utf8.txt", "" )

El motivo de usar strsplit es que es una función que puede fallar catastróficamente cuando encuentra caracteres codificados incorrectamente (desde el punto de vista de la codificación de la plataforma en la que se ejecuta).

La primera y la quinta llamada funcionan correctamente tanto en Linux como en Windows: a la función scan se le ha especificado la codificación correcta del fichero y lo ha transformado adecuadamente.

Las llamadas segunda y cuarta fallan en ambos sistemas: equivale a engañar a R y es natural que los resultados sean… subóptimos.

Las llamadas tercera y sexta son más interesantes: en Linux falla tercera y funciona la sexta; en Windows ocurre lo contrario. El motivo es que si no se especifica la codificación, R asume que es la natural del sistema (aunque supongo que se podrá configurar de alguna manera, algo en lo que no entro). Es decir, en Linux no especificar la codificación equivale a asumir utf-8 y en Windows, latin1.

Este es un detalle a tener en cuenta por quienes aspiran a desarrollar código portable, es decir, que puede ser usado por cualquiera y en cualquier plataforma para leer archivos de texto.

Nota: este experimento tiene que ver con el desarrollo del paquete pxR, que debería ser capaz de leer ficheros (y ejecutar strsplit sobre sus cadenas, entre otras funciones) en la plataforma de elección de sus usuarios (y sobre la que los autores no tenemos control). Aparentemente, los ficheros PC-Axis que queremos leer en R, según la documentación oficial, están en codificados en formato Windows.

Nuestra actual implementación está basada en ideas extraidas del experimento anterior. Si alguien ve un error en las conclusiones (o conoce una manera más adecuada para garantizar la portabilidad), le rogaría que se pusiese en contacto conmigo para trasladarla al código.