Charsets y Encodings

De Recursos Educativos
Revisión del 11:57 1 abr 2018 de Lantolin (discusión | contribs.)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)
Ir a la navegación Ir a la búsqueda

Juegos de caracteres y codificaciones.

Es un tema que puede ser confuso y lioso. Este es mi intento de aclarar términos y explicarlo de extremo a extremo.

Introducción y conceptos

El RFC2278 define Coded Character Set (CCS) como un mapeo entre un conjunto de caracteres abstractos y un conjunto de enteros. Es decir un CCS no es mas que una tabla que asocia glifos a números.

Ese mismo RFC define Character Encoding Scheme (CES) como una manera de transformar los enteros de un CCS en una serie de octetos.

Y en realidad con estos dos conceptos tenemos resueltos los dos problemas de representar cualquier caracter:

  1. una tabla que relaciona caracteres con números
  2. una manera de que si esos números son mayores que un octeto (255) los transformemos en octetos, y de octetos al número

Ejemplos de CCS: ASCII, Unicode, ISO-10646, ISO-8859, etc.

Ejemplos de CES: UTF-8, UCS-2, UCS-4, etc.

CCSs: ISO-10646 y Unicode

El ISO-10646 definió el Universal Character Set (UCS). Es un CCS que mapea glifos a enteros de 32 bits (4 bytes).

Unicode fue un esfuerzo paralelo. A partir de Unicode 2.0 se unifican. A día de hoy son 100% compatibles.

Lo que pretenden ambos era unificar y sustituir a los viejos e insuficientes CCSs como ASCII (7 bits) y sus extensiones locales de 8 bits, los ISO-8859-x.

Estas extensiones locales, como ISO-8859-1 (también llamado Latin1), definen los caracteres del 129 al 255. Este [enlace explica estupendamente estos ISO.

En resumen, es sorprendente saber cuantos años hemos ido tirando con 127 caracteres (ASCII), y luego con el empujon de 127 más (varios ISO-8859-x), hasta que por fin tenemos un estandar que cubre la representación de cualquier glifo posible (Unicode o ISO-10646).

Encodings: UTF-8

Pero aquí surge el problema, los ordenadores y las redes, por su arquitectura, están acostumbrados a manejar octetos, las representaciones de información de más de 8 bits les dan problemas así que necesitan métodos fiables de transformar enteros mayores de 255 a octetos.

Eso es lo que hace UTF-8 (UCS Transformation Format), que es un CES que transforma los enteros del Unicode (un CCS) en secuencias de bytes.

Ojo, aqui suele venir la confusión, a veces se entiende UTF-8 como una tabla de caracteres (CCS), y no lo es, es un Encoding (CES). El error es comprensible porque el UTF-8 implica usar Unicode, que si es una tabla de caracteres.

UTF-8 no es el único CES, hay otros como UTF-12 o UCS-2.

Ejemplos

Estos 12 glifos:

ÁÉÍÓÚÑáéíóúñ

En el CCS ISO-8859-1 serían:

00000000  c1 c9 cd d3 da d1 e1 e9  ed f3 fa f1              |............|

Nótese como son todos mayores de 127 (caen fuera de ASCII), pero menores que 255. Como se trata de un CCS de un solo byte no necesita encoding, se almacena tal cual, ocupan 12 bytes.

Algo similar obtenemos con:

$ echo -n Ññ | iconv -t ISO-8859-1 -f UTF-8 -t ISO-8859-1  | od --endian=big -x
0000000 d1f1

Explicación: imprimimos (sin salto de carro) los caracteres Ñ y ñ. Como estamos en un Linux moderno (Debian 8) el terminal ya trabaja en UTF-8, así que convertimos a un juego de caracteres de 8 bits y luego representamos el resultado en hexadecimal. Resultado, los índices de la ñ y la Ñ en la tabla de caracteres ISO-8859-1.

Si vieramos un fichero escrito en UTF-8 con esos mismos 12 glifos, veríamos esto:

00000000  c3 81 c3 89 c3 8d c3 93  c3 9a c3 91 c3 a1 c3 a9  |................|
00000010  c3 ad c3 b3 c3 ba c3 b1                           |........|
00000018

Aquí vemos con un solo glifo (Á) da lugar a más de 1 byte (C3 81). Por tanto la representación de estos 12 glifos en UTF-8 ocupa 24 bytes.

Es lo mismo que obtenemos si hacemos:

$ echo -n Ññ | od --endian=big -x
0000000 c391 c3b1

Por último como ejemplo de otras codificaciones veamos lo que ocurre si usamos UCS-2 y UCS-4:

$ echo -n Ññ | iconv -f UTF-8 -t UCS-2 | od --endian=big -x
0000000 d100 f100
$ echo -n Ññ | iconv -f UTF-8 -t UCS-4 | od --endian=big -x
0000000 0000 00d1 0000 00f1

Estas son codificaciones muy triviales que para los números bajos se limitan a añadir ceros hasta completar los 2 o 4 bytes.

Lenguajes de programación

Desde el punto de vista de los lenguajes y como representan internamente Unicode hay dos aproximaciones. Una es usar cadenas de enteros de 4 bytes (wchar[]) de ese modo se almacena un caracter Unicode por cada wchar sin ninguna transformación. Otra es usar cadenas de bytes (char[]) y guardar la transformación UTF-8 de los caracteres Unicode.

Herramientas de conversion

Este artículo presenta multiples maneras.

Iconv es una, recode es otra.

Ejemplos:

recode UTF-8..ISO-8859-1 fichero-en-utf-8-que-acabara-como-iso.txt 
recode ISO-8859-1..UTF-8 fichero-en-iso-que-acabara-como-utf-8.txt 

Referencias

UTF-8 and Unicode FAQ for Unix/Linux

Notas manuscritas originales de la primera vez que me puse a entender esto: