¿Cómo funciona la “codificación de ancho variable” UTF-8?

110

El estándar Unicode tiene suficientes puntos de código que necesita 4 bytes para almacenarlos todos. Eso es lo que hace la codificación UTF-32. Sin embargo, la codificación UTF-8 de alguna manera los comprime en espacios mucho más pequeños al usar algo llamado "codificación de ancho variable".

De hecho, logra representar los primeros 127 caracteres de US-ASCII en un solo byte que se ve exactamente como ASCII real, por lo que puede interpretar una gran cantidad de texto ascii como si fuera UTF-8 sin hacerle nada. Buen truco. ¿Entonces, cómo funciona?

Voy a hacer y responder mi propia pregunta aquí porque acabo de leer un poco para resolverlo y pensé que podría ahorrarle tiempo a alguien más. Además, tal vez alguien pueda corregirme si me equivoco.

dsimard
fuente
8
Unicode directo no requiere 32 bits para codificar todos sus puntos de código. Una vez reclamaron tantos puntos de código posibles, pero después de que UTF-8 despegó, se limitaron intencionalmente a 21 bits, de modo que UTF-8 nunca superará los 4 bytes por carácter. Unicode actualmente requiere solo 17 bits para contener todos los puntos de código posibles. Sin esta limitación, UTF-8 podría haber pasado a 6 bytes por carácter.
Warren Young
@Warren: mayormente preciso, pero Unicode es un código de 21 bits (U + 0000 a U + 10FFFF).
Jonathan Leffler
2
@Warren: UTF-8 limitado a 4 bytes podría haber admitido hasta U + 1FFFFF. La restricción a U + 10FFFF se hizo por el bien de UTF-16.
dan04
@ dan04 ¿Tenemos alguna explicación sencilla de cómo está restringido a U + 10FFFF por UTF-16? Sería bueno saber más sobre esto.
A-letubby
@ A-letubby: Debido a que los códigos "sustitutos" UTF-16 se asignan de tal manera que hay 1024 sustitutos principales y 1024 sustitutos de seguimiento (y solo se pueden usar en pares), para hacer 2 ^ 20 (aproximadamente un millón) de caracteres adicionales disponible más allá del BMP. Agregado a los 2 ^ 16 caracteres disponibles en el BMP, esto hace que 0x110000 caracteres posibles.
dan04

Respuestas:

129

Cada byte comienza con unos pocos bits que le indican si es un punto de código de un solo byte, un punto de código de varios bytes o una continuación de un punto de código de varios bytes. Me gusta esto:

0xxx xxxx    A single-byte US-ASCII code (from the first 127 characters)

Los puntos de código de múltiples bytes comienzan cada uno con unos pocos bits que esencialmente dicen "oye, también necesitas leer el siguiente byte (o dos, o tres) para averiguar qué soy". Son:

110x xxxx    One more byte follows
1110 xxxx    Two more bytes follow
1111 0xxx    Three more bytes follow

Finalmente, los bytes que siguen a esos códigos de inicio se ven así:

10xx xxxx    A continuation of one of the multi-byte characters

Dado que puede saber qué tipo de byte está mirando desde los primeros bits, incluso si algo se estropea en algún lugar, no pierde toda la secuencia.

dsimard
fuente
14
Hay más en la historia que eso, porque la codificación debe ser la codificación más corta posible para el carácter, lo que significa que los bytes 0xC0 y 0xC1 no pueden aparecer en UTF-8, por ejemplo; y, de hecho, tampoco 0xF5..0xFF. Consulte las preguntas frecuentes sobre UTF-8 en unicode.org/faq/utf_bom.html , o unicode.org/versions/Unicode5.2.0/ch03.pdf
Jonathan Leffler
2
¿Por qué no podía usar un solo carácter para decir next char is continuation? Si obtuviéramos un carácter de 3 bytes, sería como:, 1xxxxxxx 1xxxxxxx 0xxxxxxxpor lo que se desperdiciaría menos espacio.
9
@Soaku hace de UTF-8 un código de "auto-sincronización". Esto significa que si debido a errores faltan partes de la secuencia, es posible detectarlo y descartar lo que se haya distorsionado. Si lee un byte que comienza con 10xx y no hay un byte de "inicio" precedente, puede descartarlo porque no tiene sentido. Si tuviera un sistema como el que describió y se pierde uno de los primeros bytes, podría terminar con un carácter válido diferente sin indicación de ningún tipo de error. También facilitará la localización del siguiente carácter válido, así como la corrección de los bytes de "continuación" que faltan.
htmlcoderexe
9

RFC3629 - UTF-8, un formato de transformación de ISO 10646 es la autoridad final aquí y tiene todas las explicaciones.

En resumen, varios bits en cada byte de la secuencia de 1 a 4 bytes codificada en UTF-8 que representa un solo carácter se utilizan para indicar si es un byte final, un byte inicial y, de ser así, cuántos bytes siguen. Los bits restantes contienen la carga útil.

azheglov
fuente
1
Ummmm, tonto de mí, pensé que el estándar Unicode era la autoridad final en UTF-8
John Machin
6
El estándar Unicode define el propio Unicode. No define varios métodos, actuales y futuros, que pueden usarse para codificar textos Unicode para una variedad de propósitos (como almacenamiento y transporte). UTF-8 es uno de esos métodos y la referencia anterior es al documento que lo define.
azheglov
1
RFC3629, página 3, sección 3. dice "UTF-8 está definido por el estándar Unicode".
John Machin
La búsqueda de enlaces en unicode.org me llevó a la sección 3.9 del estándar Unicode y específicamente a la definición D92 (y también tangencialmente D86). No tengo idea de hasta qué punto este enlace será útil cuando se publiquen nuevas versiones, pero me imagino que quieren mantener estables los identificadores de sección y definición en todas las versiones.
tripleee
4

UTF-8 fue otro sistema para almacenar su cadena de puntos de código Unicode, esos números mágicos U +, en la memoria usando bytes de 8 bits. En UTF-8, cada punto de código de 0-127 se almacena en un solo byte. Solo los puntos de código 128 y superiores se almacenan utilizando 2, 3, de hecho, hasta 6 bytes.

Extracto del mínimo absoluto que todo desarrollador de software debe conocer absoluta y positivamente sobre Unicode y conjuntos de caracteres (¡sin excusas!)

Andrés
fuente
Es un buen artículo, pero parece que Joel se equivoca con respecto a la longitud máxima de la secuencia; la página de Wikipedia muestra 1..4 bytes por carácter, únicamente.
relajarse el
4
Como dije anteriormente, cuando se creó UTF-8 por primera vez, Unicode reclamó hasta 32 bits para los puntos de código, no porque realmente lo necesitaran, solo porque 32 bits es un valor conveniente y ya habían superado el límite anterior de caracteres de 16 bits. Después de que UTF-8 se hizo popular, decidieron limitar para siempre el número máximo de puntos de código a 2 ^ 21, que es el valor más grande que puede codificar con 4 bytes del esquema UTF-8. Todavía hay menos de 2 ^ 17 caracteres en Unicode, por lo que podemos cuadruplicar el número de caracteres en Unicode con este nuevo esquema.
Warren Young
Ok, pero no la explicación solicitada por OP.
Nishant
2
Esto no responde a la pregunta.
Koray Tugay