Códigos de caracteres, unicode y UTF-8

Unos quebraderos de cabeza en el desarrollo del paquete pxR concernientes a los distintos códigos de caracteres en que hay que transfomar los datos me han obligado a profundizar en este enojoso asunto.

En el principio, todo era felicidad. Existía el código ASCII que establecía una correspondencia entre caracteres, números y su representación binaria. Así, a la letra b le correspondía el número 98 cuya codificación binaria es el byte 01100010.

Felicidad que se interrumpió cuando algún ortógrafo quiso utilizar eñes y acentos. Y algún tailandés a escribir su nombre como había aprendido en la escuela. Etc. De ahí surgió el caos de los múltiples sistemas y codificaciones: que si el ISO-8859-1, que si el KOI 8, que si el de IBM, que si el de Microsoft,… todos ellos intentos de codificar distintos codificar distintos caracteres usando las 256 combinaciones que permiten los 8 bits de un byte mediante funciones biyectivas

$$f_i: C_i \longleftrightarrow B_1$$

entre $latex B_1$, el conjunto de los distintos bytes (números del 0 al 255), y diversos conjuntos de caracteres ($latex C_1$ pueden ser los latinos, $latex C_2$ los rusos, etc.).

Y del caos surgió la luz y el orden, una función biyectiva

$$C = \bigcup_i C_i \longleftrightarrow N = {0, \dots, 1114112}$$

llamada Unicode entre todos los caracteres del mundo mundial y los números hasta el 1.114.112. Esta función hace corresponder el número 88 a “X” y 241 a “ñ”, por ejemplo.

Para tener una representación binaria de un caracter, sin embargo, es necesaria otra función. Y no una función trivial: si este tinglado lo hubiese montado un gañán, harían falta tres bytes por caracter, con lo que el tamaño de los ficheros de texto se multiplicaría automáticamente.

La solución pasa por seleccionar inteligentemente la función entre el conjunto $latex N$ y determinadas sucesiones de bytes. Una de las funciones propuestas se llama UTF-8, que tiene la peculiaridad de que asigna los números correspondientes a los caracteres más usados a secuencias de ocho bits (un byte) y a los menos usados, secuencias de dos, tres y hasta cuatro de ellos.

Así, usando dicha función, la “X” ocupa un único byte, pero “ñ” ocupa dos. Y supongo que los caracteres chinos ocuparán dos o tres.

Este es el motivo por el que cuando alguien intenta leer un fichero codificado con UTF-8 como si tuviese una codificación que asume una relación directa entre caracteres y bytes, obtiene los famosos caracteres raros en lugar de sus acentos, eñes y demás.

Han sido muchos los años en que nos hemos dejado arrastrar por la inercia un byte, un caracter (aunque no tenemos ni idea de cuál). Ahora la hemos sustituido por la composición de dos funciones, Unicode y UTF-8 que, gracias a Dios, están bien pensadas.