¿Por qué UTF-8 desperdicia varios bits en su codificación?

17

Según el artículo de Wikipedia , UTF-8 tiene este formato:

Primer código Último código Bytes Byte 1 Byte 2 Byte 3 Byte 4
punto punto utilizado
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2 110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x significa que este bit se usa para seleccionar el punto de código.

Esto desperdicia dos bits en cada byte de continuación y un bit en el primer byte. ¿Por qué UTF-8 no está codificado como el siguiente?

Primer código Último código Bytes Byte 1 Byte 2 Byte 3
punto punto utilizado
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3110xxxxx xxxxxxxx xxxxxxxx

Ahorraría un byte cuando el punto de código está fuera del plano multilingüe básico o si el punto de código está dentro del rango [U + 800, U + 3FFF].

¿Por qué UTF-8 no está codificado de una manera más eficiente?

qbt937
fuente
3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt Su codificación propuesta es similar a la propuesta original de FSS / UTF. Ken Thompson y Rob Pike querían la propiedad de sincronización automática.
ninjalj
44
Además, su codificación no parece garantizar que los valores del código ASCII no aparezcan en ninguna parte de la representación de caracteres no ASCII. FSS / UTF y UTF-8 están diseñados para trabajar con programas heredados (por ejemplo: aquellos que usan ASCII NUL y barra inclinada (separador de ruta) como separadores).
ninjalj

Respuestas:

26

Esto se hace para que pueda detectar cuándo se encuentra en medio de una secuencia de varios bytes. Cuando observa los datos UTF-8, sabe que si ve 10xxxxxx, se encuentra en el medio de un carácter multibyte y debe retroceder en la secuencia hasta que vea uno 0xxxxxxu otro 11xxxxxx. Usando su esquema, los bytes 2 o 3 podrían terminar fácilmente con patrones como 0xxxxxxxo11xxxxxx

También tenga en cuenta que cuánto se guarda varía completamente según el tipo de datos de cadena que está codificando. Para la mayoría del texto, incluso el texto asiático, rara vez verá, si alguna vez, caracteres de cuatro bytes con texto normal. Además, las estimaciones ingenuas de las personas sobre cómo se verá el texto a menudo son incorrectas. Tengo texto localizado para UTF-8 que incluye cadenas japonesas, chinas y coreanas, pero en realidad es el ruso el que ocupa más espacio. (Debido a que nuestras cadenas asiáticas a menudo tienen caracteres romanos intercalados para nombres propios, signos de puntuación y demás, y porque la palabra china promedio es de 1-3 caracteres, mientras que la palabra rusa promedio es muchos, muchos más).

Gort the Robot
fuente
Pero con mi esquema, si comienzas en una ubicación que se sabe que está al principio de un personaje, entonces puedes saber cuántos bytes hay en el personaje y llegar al inicio del siguiente personaje.
qbt937
11
Seguro. Su esquema es más denso en información pero no tiene una característica importante que UTF-8 proporciona. En general, las personas prefieren la seguridad, por eso es posible UTF-8. Además, para demostrar realmente que su esquema es realmente más eficiente, desearía proporcionar estadísticas usando texto real. Es muy posible que en la mayoría de los textos reales, su esquema ahorre una cantidad muy trivial y, por lo tanto, los ahorros no valgan la pena.
Gort the Robot el
3
Otra característica importante: si no hay un punto de código de cero incrustado, no hay ceros incrustados en la cadena.
Deduplicador
Para el script tailandés, debe permitir 4 bytes por carácter impreso. No solo llegaron tarde a la fiesta, sino que también obtuvieron un grupo de códigos numerados. Muchas cosas que parecen un solo carácter cuando se imprimen están compuestas de tres caracteres unicode diferentes.
James Anderson el
@ qbt937: Usando su esquema, ¿cómo se escanearía rápidamente para averiguar si una cadena contiene otra?
supercat
6

La forma oficial le permite al decodificador saber cuándo está en el medio de la tupla y sabe omitir bytes (o ir hacia atrás) hasta que el byte comience con 0o 11; Esto evita los valores basura cuando un solo byte se corrompe.

monstruo de trinquete
fuente
3

Respuesta corta, su propuesta no diferencia entre el primer byte y los bytes de continuación.

El patrón de bits en el extremo superior del primer byte le indica con cuántos bytes se construye el carácter real. Estos patrones también proporcionan cierto reconocimiento de errores al analizar una cadena. Si está leyendo (aparentemente) el primer byte de un personaje y obtiene 10xxxxxx, entonces sabe que no está sincronizado.

Kitana
fuente
2

Lo que no se ha mencionado es que si tiene una secuencia correcta de puntos de código y un puntero que está garantizado para apuntar al primer byte de un punto de código, con UTF-8 puede encontrar fácilmente el puntero al primer byte del punto de código anterior (omita todos los bytes que comienzan con 01xx xxxx). Con su codificación, es imposible sin examinar potencialmente todos los bytes hasta el comienzo de la cadena.

Considere las secuencias de (2n + 2) bytes

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

y

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

Si tiene un puntero al primer byte del primer punto de código después de esta secuencia, debe examinar todos los bytes para averiguar si el último punto de código es 0xxxxxxx o (10xxxxxx, 0xxxxxxx).

En realidad, existen esquemas de codificación más eficientes, en los que se puede ir al punto de código anterior en tiempo constante y se pueden corregir los punteros al centro de un punto de código. Permitir los siguientes códigos:

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

Si uno de los tres bytes anteriores es ≥ 236, entonces es el comienzo de una secuencia de 3 bytes, porque no puede haber dos bytes dentro de una secuencia válida de 3 bytes. De lo contrario, si uno de los dos bytes anteriores es ≥ 128, entonces es el comienzo de una secuencia de dos bytes. De lo contrario, el byte anterior es un solo byte <128.

La búsqueda de una subcadena se vuelve un poco más difícil. Es posible que desee excluir cero bytes para que una cadena solo contenga un byte cero si contiene un punto de código cero.

gnasher729
fuente
Lo que no se ha mencionado ... , no realmente, ya que esto se deduce directamente de la observación hecha en la respuesta de @ratchet freak.
Piotr Dobrogost