CiberInfo

Introducción a UTF-8
(UNICODE Transformation Format)

Windows puede trabajar con cadenas Unicode, SBCS y DBCS, pero el kernel de Linux trabaja con cadenas UTF-8, donde un carácter puede ocupar hasta seis bytes. Normalmente uno o dos en idiomas occidentales y de uno a tres en idiomas asiáticos. UTF-8 es un esquema de codificación multibyte que puede acomodar todos los caracteres del UCS (Universal Character Set - Juego de Caracteres Universal), que contiene caracteres de 31 bits capaces de representar prácticamente todos los caracteres de idiomas vivos y lenguas muertas, incluídos los ideogramas como Hiragana, Kiragana, etc. También deja espacio para más lenguajes, scripts y jeroglíficos.
UTF-8 presenta las siguientes características importantes:
  • Codificación de longitud variable para caracteres UCS. UTF-8 puede codificar caracteres UCS (ISO 10646) en hasta 6 bytes.

  • Transparencia y univoquidad para caracteres ASCII
    Los caracteres ASCII de 7 bits (#0..#127) son codificados directamente como caracteres ASCII de 7 bits (1 byte por carácter). Todos los caracteres no ASCII (#128..#255) se representan como valores de 8 bits no ASCII (#128..#255) para que los caracteres no ASCII no puedan confundirse con caracteres ASCII, y las herramientas de procesamiento de texto basadas en ASCII puedan ser usadas con texto UTF-8 siempre y cuando dejen pasar los caracteres de 8 bits sin interpretación.

  • El carácter nulo
    El carácter #0 (ASCII NULL) sólo aparece donde se desea un nulo. No puede ser un byte líder o un byte de relleno por ejemplo.

  • Auto-sincronización para procesamiento de alta velocidad
    Los patrones de los bits de alto orden desambiguan los límites de los caracteres, y hace fácil saber si un simple byte es un carácter de un solo byte (0xxxxxxx), un byte líder (11yyyyyx) o un byte de relleno (10xxxxxx). Este aspecto es muy importante porque permite que las funciones que procesan caracteres UTF-8 sean más eficientes que las funciones para DBCS de Windows. Por ejemplo, una cadena UTF-8 puede recorrerse hacia atrás y las búsquedas de un carácter multibyte que comience con un byte principal nunca terminarán en un byte de relleno en medio de un carácter multibyte no deseado. Y como el byte líder anuncia la longitud del carácter multibyte, puede contar rápidamente cuántos bytes saltar al recorrer hacia adelante.

  • Amistoso con el procesador
    UTF-8 se puede leer y escribir rápidamente con simples operaciones de enmascaramiento y desplazamiento de bits sin multiplicaciones ni divisiones (que son operaciones lentas para el procesador).

  • Compresión razonable
    UTF-8 no es tan compacto como las DBCS de Windows, pero para lenguajes occidentales es mejor que Unicode, y en el peor de los casos (idiomas asiáticos) nunca es peor que UCS-4.

  • Ordenamiento canónico
    UTF-8 conserva el orden de comparación para rutinas simples de comparación de 8 bits como strcmp (una función estándar del C).

  • Caracteres centinela
    Los bytes #$FE y #$FF nunca aparecen, así que los puede usar como centinelas, banderas, señales o para indicar un significado especial (evitando la posibilidad de confundir un centinela con un carácter verdadero).

  • Detectabilidad
    Es fácil de detectar una entrada UTF-8 con alta probabilidad si ve la firma #$EF#$BB#$BF ('') o si ve caracteres multibyte UTF-8 válidos dado que es improbable que accidentalmente aparezcan en texto ISO 8859-1 (Latin-1).

Codificación UTF-8

Este es el formato general usado para codificar caracteres UCS en UTF-8:
 Bits  Bytes  Representación
   7     1    0xxxxxxx
  11     2    110xxxxx  10xxxxxx
  16     3    1110xxxx  10xxxxxx  10xxxxxx
  21     4    11110xxx  10xxxxxx  10xxxxxx  10xxxxxx
  26     5    111110xx  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx
  31     6    1111110x  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx  10xxxxxx
Nótese que el número de bits 1 en el byte líder es el número de bytes en una secuencia multibyte.

El signo de copyright ('©' = #169 = #$A9) en binario es 10101001 y dado que necesita 8 bits, tenemos que usar dos bytes:

110xxxxx 10xxxxxx

Tenemos que llenar entonces 11 bits (x), así que le agregamos tres ceros a la izquierda a 10101001:

00010 101001

La representación UTF-8 para el carácter de copyright entonces sería:

11000010 10101001

Podría también representarse con más bytes de lo necesario en secuencias de cadena "extra-largas" (overlong). Por ejemplo, con cuatro bytes, sería:


                  11110xxx  10xxxxxx  10xxxxxx  10xxxxxx
                       000    000000    000010    101001
                 ----------------------------------------
                  11110000  10000000  10000010  10101001

Las secuencias extra-largas se usan para "camuflar" caracteres y "engañar" comprobaciones de subcadenas. Por ejemplo, si busca el signo de copyright exactamente como 11000010 10101001 (la codificación más corta posible), entonces no lo encontrará.

Longitud de una cadena UTF-8

En Delphi para Linux, las cadenas largas estarán en formato UTF-8, mientras que las cadenas anchas permanecerán como Unicode de dos bytes. Para saber el número real de caracteres almacenados en una cadena UTF-8 podríamos usar una función como la siguiente:

  function UTF8Length(const s: string): integer;
  var
    i, n: integer;
    c: byte;
  begin
    Result := 0;
    n := Length(s);
    i := 1;
    while i <= n do begin
      inc(Result);
      c := byte(s[i]);
      if (c and $80) = 0 then inc(i)
      else if (c and $E0) = $C0 then inc(i, 2)
      else if (c and $F0) = $E0 then inc(i, 3)
      else if (c and $F8) = $F0 then inc(i, 4)
      else if (c and $FC) = $F8 then inc(i, 5)
      else if (c and $FE) = $FC then inc(i, 6)
      else
        raise Exception.Create('No es una cadena UTF-8');
    end;
    if i > n + 1 then
      raise Exception.Create('No es una cadena UTF-8');
  end;
Buha design Valid XHTML 1.0 Strict Valid CSS 2