Codificación de Caracteres
NOTA: Al preparar este texto, excedí el límite de espacio que me asignan, por lo cual después de terminar de escribir tuve que ver qué párrafos eran más prescindibles. Acá reproduzco el artículo completo, y adjunto como archivo la versión tal cual apareció impresa.
<p>Hace un par de días recibí uno de esos correos que parecen venir de una época ya superada y olvidada hace años: Un correo que comenzaba con la frase:</p>
<blockquote>Para evitar problemas de compatibilidad, este correo no incluye acentos ni enies</blockquote>
<p>En efecto, este problema casi ha desaparecido del correo, y ese pretexto sencillamente ya no resulta ni siquiera una excusa adecuada para quien le da flojera escribir el español correctamente.</p>
<p>Sin embargo, no en todos los campos podemos hablar de un éxito tan grande como en el manejo del correo electrónico — Y es de esperarse. La naturaleza misma del correo lo requiere. Cada mensaje individual debe ser transportado, sin que le sean inflingidas modificaciones por agentes externos, entre los equipos de los participantes en una conversación — que pueden estar configuradas con referentes culturales completamente distintos.</p>
<p>Y si bien para los hispanoparlantes, especialmente para aquellos que sienten que el uso de <em>símbolos internacionales</em> (acentos, tildes y signos de apertura de interrogación/exclamación) es opcional, el correo funcionó <em>casi bien</em> desde un principio (y a continuación detallaremos el por qué), cuando el uso de Internet dio su gran salto cuantitativo en los 1990s y llegó a la población en general, para los nativos de muchas otras culturas alrededor del mundo se hizo imperativo encontrar cómo comunicarse confiablemente.</p>
<p>Pero el problema viene de mucho más atrás. Repasemos rápidamente la historia de los esquemas de codificación de caracteres.</p>
<h3>Repaso histórico</h3>
<p>La codificación a partir de la cual se originan todos los esquemas en uso hoy en día nació en 1963, revisado/ratificado en 1967 con el nombre de ASCII: <em>Código Estándar Americano para el Intercambio de Información</em>. ASCII es un código de 7 bits, permitiendo la representación de hasta 128 caracteres, y en su versión definitiva incluye 32 caracteres de control, 34 símbolos, 52 caracteres de texto (mayúsculas y minúsculas) y 10 dígitos.</p>
<p>Sobra decir que el ámbito cómputo ha cambiado drásticamente desde 1963. La computadora debía representar apenas la información indispensable para ser comprendida por sus operadores, y en la propuesta original, ASCII no incluía ni siquiera letras minúsculas <span class="ref"(Jennings 1999-2004)</span>. Pero ya en 1964 aparecieron las máquinas de escribir IBM MT/ST: Una máquina de escribir electrónica, con la capacidad de guardar (y corregir) páginas en cinta magnética. Fue sólo cuestión de tiempo (y del necesario paso de popularización que siguió a la revolución de las computadoras personales hacia fines de los 1970) para que estas capacidades quedaran al alcance de todo mundo.</p>
Y es ahí donde se hizo obvio que haría falta extender ASCII: Todos los idiomas europeos que utilizan el alfabeto latino a excepción del inglés requieren de diferentes tipos de diacríticos para ser representados; tras varias ideas descartadas, se aprovechó el hecho de que hacia fines de los 1970 todas las computadoras ampliamente desplegadas tenían un tamaño de palabra de 8 bits para utilizar un ASCII ampliado que daría 128 caracteres adicionales. Sin embargo, la idea resonó rápidamente… Y no surgió un estándar para su uso. Además, muchos de estos caracteres fueron empleados para incluir caracteres gráficos, para permitir construir interfaces amigables al usuario.
En 1981, IBM puso a la venta su primer computadora personal - La IBM 5051, o como se popularizó, la PC. Entre sus características contaba con una tarjeta de video con páginas de códigos reprogramables — La mitad superior del espacio de caracteres podía ser definida por software; los caracteres cargados por omisión eran los de la página de códigos 437 (CP437), con soporte parcial para algunos lenguajes europeos, pero –debido al espacio empleado por los caracteres semigráficos para representar interfaces al usuario– nunca fueron suficientes, por lo que en general era necesario activar una página de código alternativa — Para el español, la CP850. La situación mejoró al popularizarse los entornos gráficos y dejar de depender de los caracteres semigráficos; varias hojas de código relacionadas pudieron agruparse en un menor número — En este caso, para lenguajes europeos occindentales, la ISO-8859-1.
El problema se presenta al intercambiar archivos con usuarios de otras páginas: Los datos que usan una página son indistinguibles que los que usan otra. Si compartiera un archivo ISO-8859-1 con una persona de Europa oriental (ISO-8859-2), los caracteres acentuados aparecerían modificados, aparentemente corruptos. La situación de los lenguajes de Asia oriental era mucho peor aún, dado que por la cantidad de glifos, plantear el uso de un alfabeto de 256 caracteres resultó imposible — y por muchos años, la interoperabilidad fue meramente un sueño.
En 1988, Joe Becker, Lee Collins y Mark Davis, de Xerox y Apple, se reunieron para atacar este problema de raiz: Lanzaron la iniciativa del sistema Unicode, buscando aprovechar los grandes avances de más de 20 años del cómputo para lograr un conjunto de caracteres apto para todo el mundo. Pronto su iniciativa logró captar la atención y el respaldo de otros líderes del desarrollo del cómputo.
El desarrollo de Unicode no está libre de desaciertos y peleas políticas, pero el resultado bien lo valió: Para 1996 se publicó la especificación Unicode 2.0, permitiendo un espacio de más de un millón (216+220) de puntos de código independientes, reteniendo compatibilidad hacia atrás completa con el principal esquema heredado (ISO-8859-1), derivado de CP850.
Unicode es tan grande que su representación interna no está libre de polémica e interpretaciones. Sin entrar en detalles técnicos, las dos principales representaciones son UTF-8 (utilizada en sistemas basados en Unix, y en general, para toda transmisión sobre redes de datos) y UTF-16, descendiente de UCS-2 (en uso principalmente en sistemas Windows).
No entraré mucho en detalles respecto a estas dos representaciones — Es sólo importante estar conscientes de que una cadena Unicode puede estar representada internamente de diferentes maneras; UTF-8 está basado en elementos individuales de 8 bits, mientras que el átomo en UTF-16 es de 16 bits, por lo que –especialmente con idiomas basados en el alfabeto latino– UTF-8 es más compacto (con UTF-16, el byte superior consistirá sólamente de ceros) y es sensiblemente más robusto para transmisiones sobre la red (una corrupción de datos afecta un punto mínimo, mientras que con UTF-16 puede hacer ilegible todo el texto a partir de ese punto).
Un punto importante a mantener en cuenta es que la representación binaria de texto ASCII heredado es idéntica a su representación en UTF-8 — No así con UTF-16. Para más detalles respecto a estas dos representaciones, así como las otras varias posibles, sugiero leer (Wikipedia Comparación).
¿Qué hace diferente al tratamiento de Unicode?
Hasta antes de Unicode, todo lo que teníamos que saber respecto a un esquema de codificación se limitaba a elegir la salida adecuada, o interpretar la entrada como debía ser. Y Unicode agrega muchos puntos a la mezcla. algunos de ellos:
<dl>
<dt>Longitud de una cadena</dt>
<dt>No todas las cadenas son válidas</dt>
Si han visto una página Web donde los caracteres con diacríticos aparecen substituídos por caracteres en forma de rombo con un signo de interrogación dentro (�, punto de código U+FFFD), éste caracter denota que el procesamiento de Unicode no pudo completarse. Sin embargo, no todas las aplicaciones son tan benignas como un navegador — Una base de datos, por ejemplo, debe negarse a guardar datos mal-formados, por lo cual debemos estar conscientes del tipo de excepciones que posiblemente recibiremos si nuestro usuario nos da datos inválidos.
<dt>Caracteres definidos semánticamente, no visualmente</dt>
<dd>Los caracteres en Unicode no buscan únicamente representar un grupo de grafías, sino que su significado. En tiempos del ASCII nos acostumbramos a utilizar la <em>representación gráfica</em> más cercana a un caracter. Por ejemplo, nos acostumbramos a representar a la multiplicación con el asterisco ya sea con la letra «x» o con el asterisco; con Unicode podemos usar –cual debe ser– el símbolo <span class="uchar">✕</span> (U+2715). Los alemanes ya no se ven forzados a usar la <span class="uchar">β</span> (beta griega, U+0392) en vez de la <span class="uchar">ß</span> (<em>Eszett</em> o <em>S fuerte</em>, U+00DF).<br/> Si bien esto es más una ventaja que nada, puede llevarnos a confusiones. Por ejemplo, si bien en ASCII con CodePage 850 sólo podemos representar a una letra acentuada de una manera (la letra <span class="uchar">á</span> está en la posición 160), en Unicode puede representarse en este mismo punto, o como la combinación de una a minúscula (caracter 95, U+0061) y un caracter combinante de acento agudo (U+0300): <span class="uchar">á</span>. Esto permite la gran expresividad que requieren algunos idiomas o alfabetos (ver <span class="ref">(Wood 1999-2009)</span> con una clara ejemplificación de la expresividad que otorgan), pero nos obliga a considerar más casos especiales al enfrentarnos a Unicode desde el punto de vista del desarrollador de sistemas.</dd>
</dl>
<h3>Promesas, promesas…</h3>
<p>Como ya lo hemos discutido en este mismo espacio, el punto que más debemos cuidar como desarrolladores son los puntos de cruce — Las barreras, las <em>costuras</em> en la realidad. Lo ideal sería que no hiciera falta que un componente le dijera explícitamente al otro que está listo y dispuesto para usar Unicode. Un sistema operativo instalado limpiamente el día de hoy, así como casi cualquier aplicación que instalemos sobre de éste, debe funcionar bien –y de manera predeterminada– con Unicode. Claro está, la realidad siempre se interpone — Por un lado, podemos tener que interactuar con componentes <em>heredados</em>. Por otro lado, no podemos olvidar el hecho de que muy rara vez podemos controlar el entorno de nuestros usuarios — Y por último, un punto donde nos toparemos ineludiblemente con problemas de codificación es al hablar con dispositivos externos.</p>
<p>Si bien es posible aplicar reglas heurísticas para determinar si una cadena es válida o no como UTF-8 <span class="ref">(Dürst 1997)</span>, prácticamente cualquier protocolo que utilicemos hoy en día para transmitir contenido que deba ser interpretado como texto proporciona un campo en su encabezado para indicar el tipo de contenido a utilizar — Sin olvidar tomar en cuenta que muchos protocolos contemplan la transmisión de datos <em>multipartes</em>, ¡y cada una de las partes puede llevar codificaciones diferentes!</p>
<h3>Conclusiones</h3>
<p>Viendo sólamente estos puntos, puede que muchos de ustedes los vayan poniendo en la balanza, y les parezca que migrar a Unicode es demasiado dificil y no vale la pena. Sin embargo, sencillamente, no nos queda opción: El mundo entero va avanzando en ese sentido. </p>
<p>Si bien nos toca la parte más simple, por ser nativos de una cultura basada en el alfabeto dominante en Internet, no podemos ignorar que formamos parte de un mundo plenamente globalizado, y que los días de vivir en nuestra islita feliz de un sólo alfabeto han terminado.</p>
<p>Del mismo modo que sencillamente ya no es aceptable que una aplicación falle cuando le enviamos datos escritos correctamente acentuados, tampoco es aceptable que rechacemos registrar a personas cuyo nombre tiene origen extranjero, o que tienen una dirección de destinatario no representable con caracteres latinos. Ni es aceptable, en un mundo que tiende a la presentación de software como servicio «en la nube», no ofrecer una solución capaz de manejar los datos enviados por usuarios de todo el mundo es ofrecer una solución con baja calidad de servicio.</p>
<h3>Referencias</h3>
<ul>
<li><span class="ref">(Jennings 1999-2004)</span> Annotated history of character codes http://wps.com/projects/codes/index.html</li>
<li><span class="ref">(Dürst 1997)</span> The Properties and Promizes of UTF-8 http://www.ifi.unizh.ch/mml/mduerst/papers/PDF/IUC11-UTF-8.pdf</li>
<li><span class="ref">(Czyborra 1995-2000)</span> Unicode in the Unix Environment http://www.unicodecharacter.com/</li>
<li><span class="ref">(Wood 1999-2009)</span> Combining Diacritical Marks http://www.alanwood.net/unicode/combining_diacritical_marks.html</li>
<li><span class="ref">(Wikipedia Comparación)</span> Comparison of Unicode encodings http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings</li>
</ul>