¿Cuál es el número máximo de bytes para un carácter codificado en UTF-8?

79

¿Cuál es el número máximo de bytes para un solo carácter codificado en UTF-8?

Encriptaré los bytes de una cadena codificada en UTF-8 y, por lo tanto, necesito poder calcular el número máximo de bytes para una cadena codificada en UTF-8.

¿Podría alguien confirmar el número máximo de bytes para un solo carácter codificado en UTF-8?

Edd
fuente
1
Usted hizo vistazo a recursos comunes, tales como la Wikipedia UTF-8 del artículo , en primer lugar ... ¿verdad?
5
Leí varios artículos que dieron respuestas mixtas ... De hecho, tuve la impresión de que la respuesta era 3, así que estoy muy contento de haber preguntado
Edd
2
Dejaré un enlace de youtube aquí, con los personajes, los símbolos y el milagro Unicode de Tom Scott: goo.gl/sUr1Hf . Puede escuchar y ver cómo todo está evolucionando desde la codificación de caracteres ASCII hasta utf-8.
Roy Lee
Consulte también Cálculo de la longitud en UTF-8 de Java String sin codificarlo para el ejemplo de código de cálculo de longitud
Vadzim

Respuestas:

86

El número máximo de bytes por carácter es 4 según RFC3629 que limita la tabla de caracteres a U+10FFFF:

En UTF-8, los caracteres del rango U + 0000..U + 10FFFF (el rango accesible UTF-16) se codifican utilizando secuencias de 1 a 4 octetos.

(La especificación original permitía códigos de caracteres de hasta seis bytes para los puntos de código anteriores U+10FFFF).

Los caracteres con un código de menos de 128 requerirán solo 1 byte, y los siguientes códigos de 1920 caracteres solo requerirán 2 bytes. A menos que esté trabajando con un lenguaje esotérico, multiplicar el número de caracteres por 4 será una sobreestimación significativa.

Tamás
fuente
7
¿Qué es el "lenguaje esotérico" para ti? ¿Algún idioma que existiría en el mundo real, o un texto que cambia entre diferentes idiomas del mundo? ¿Debería un desarrollador de una función UTF-8-to-String elegir 2, 3 o 4 como multiplicador si realiza una sobreasignación y reduce el resultado después de la conversión real?
Daniel Marschall
1
@rinntech por 'lenguaje esotérico' se refiere a un idioma que tiene muchos caracteres Unicode de alto valor (algo cercano al final de esta lista: unicode-table.com/en/sections ). Si debe sobreasignar, elija 4. Puede hacer una doble pasada, una para ver cuántos bytes necesitará y asignar, luego otra para hacer la codificación; eso puede ser mejor que asignar ~ 4 veces la RAM necesaria.
matiu
9
Siempre trate de manejar el peor de los casos: hacker9.com/single-message-can-crash-whatsapp.html
Evgen Bodunov
20
Los caracteres CJKV en su mayoría toman 3 bytes (con algunos caracteres raros / arcaicos que toman 4 bytes) y llamarlos esotéricos es un poco exagerado (solo China es casi el 20% de la población mundial ...).
Tgr
3
¿Por qué se limitó a 4 cuando anteriormente era 6? ¿Qué nos impide continuar con el estándar y tener un byte inicial de 11111111y tener un 2^(6*7)poco de espacio para los caracteres?
Aaron Franke
32

Sin más contexto, diría que el número máximo de bytes para un carácter en UTF-8 es

respuesta: 6 bytes

El autor de la respuesta aceptada señaló correctamente esto como la "especificación original". Eso era válido a través de RFC-2279 1 . Como J. Cocoe señaló en los comentarios a continuación, esto cambió en 2003 con RFC-3629 2 , que limita UTF-8 a la codificación de 21 bits, que se puede manejar con el esquema de codificación usando cuatro bytes.

respuesta si cubre todo unicode: 4 bytes

Pero, en Java <= v7 , ¿hablan de un máximo de 3 bytes para representar unicode con UTF-8? Esto se debe a que la especificación Unicode original solo definía el plano multilingüe básico ( BMP ), es decir, es una versión anterior de Unicode o un subconjunto de Unicode moderno. Entonces

respuesta si representa solo unicode original, el BMP: 3 bytes

Pero, el OP habla de ir al revés. No de caracteres a bytes UTF-8, sino de bytes UTF-8 a una representación de "Cadena" de bytes. Quizás el autor de la respuesta aceptada obtuvo eso del contexto de la pregunta, pero esto no es necesariamente obvio, por lo que puede confundir al lector casual de esta pregunta.

Pasando de UTF-8 a la codificación nativa, tenemos que ver cómo se implementa la "Cadena". Algunos lenguajes, como Python> = 3, representarán cada carácter con puntos de código enteros, lo que permite 4 bytes por carácter = 32 bits para cubrir los 21 que necesitamos para Unicode, con algo de desperdicio. ¿Por qué no exactamente 21 bits? Porque las cosas son más rápidas cuando están alineadas por bytes. Algunos lenguajes como Python <= 2 y Java representan caracteres que utilizan una codificación UTF-16, lo que significa que tienen que utilizar pares sustitutos para representar unicode extendido (no BMP). De cualquier manera, sigue siendo un máximo de 4 bytes.

respuesta si va UTF-8 -> codificación nativa: 4 bytes

Entonces, conclusión final, 4 es la respuesta correcta más común, así que lo hicimos bien. Pero el kilometraje puede variar.

Joshua Richardson
fuente
5
"esta sigue siendo la especificación actual y correcta, según wikipedia", ya no. Poco después de que escribiera esto (edición del 2 de abril), el artículo UTF-8 de Wikipedia se cambió para aclarar que la versión de 6 octetos no forma parte de la especificación UTF-8 actual (2003).
J. Cocoe
"Pero, en Java <= v7, ¿hablan de un máximo de 3 bytes para representar Unicode con UTF-8? Eso es porque la especificación Unicode original solo definía el plano multilingüe básico". Esa es probablemente la razón original, pero no es toda la historia. Java usa "UTF-8 modificado", y una de las modificaciones es que "usa su propio formato de dos veces tres bytes" en lugar de "el formato de cuatro bytes del UTF-8 estándar" (sus palabras).
J. Cocoe
1
No hay puntos de código asignados por encima del límite de 10FFFF (poco más de un millón) y muchas de las implementaciones de UTF8 nunca implementaron secuencias de más de 4 bytes (y algunas solo 3, por ejemplo, MySQL), por lo que consideraría seguro limitar estrictamente a 4 bytes codepoint incluso cuando se considera la compatibilidad con implementaciones anteriores. Solo necesitaría asegurarse de descartar todo lo que no sea válido al ingresar. Tenga en cuenta que la recomendación de matiu de realizar la asignación después de calcular la longitud exacta del byte es buena siempre que sea posible.
thomasrutter
2
"... [U] nicode puede representar hasta x10FFFF puntos de código. Entonces, incluyendo 0, eso significa que podemos hacerlo con estos bytes: F FF FF, es decir, dos bytes y medio, o 20 bits". Creo que esto es un poco incorrecto. El número de puntos de código de 0x0 a 0x10FFFF sería 0x110000, que podría representarse en 1F FF FF21 bits. El número 0x110000 corresponde a los 17 planos de puntos de código 0x10000 cada uno.
neuralmer
2
PSA: Wikipedia no es una fuente real. Mira las referencias reales del artículo.
Nyerguds
0

El número máximo de bytes para admitir US-ASCII, una codificación del alfabeto inglés estándar, es 1. Pero limitar el texto al inglés se está volviendo menos deseable o práctico a medida que pasa el tiempo.

Unicode fue diseñado para representar los glifos de todos los lenguajes humanos, así como muchos tipos de símbolos, con una variedad de características de representación. UTF-8 es una codificación eficiente para Unicode, aunque todavía sesgada hacia el inglés. UTF-8 se sincroniza automáticamente: los límites de los caracteres se identifican fácilmente mediante la exploración de patrones de bits bien definidos en cualquier dirección.

Si bien el número máximo de bytes por carácter UTF-8 es 3 para admitir solo el espacio de direcciones de 2 bytes del plano 0, el plano multilingüe básico (BMP), que puede aceptarse como soporte mínimo en algunas aplicaciones, es 4 para admitir los 17 planos actuales de Unicode (a partir de 2019). Cabe señalar que es probable que muchos caracteres "emoji" populares se encuentren en el plano 16, que requiere 4 bytes.

Sin embargo, esto es solo para glifos de caracteres básicos. También hay varios modificadores, como hacer que aparezcan acentos sobre el carácter anterior, y también es posible unir un número arbitrario de puntos de código para construir un "grafema" complejo. En la programación del mundo real, por lo tanto, el uso o la suposición de un número máximo fijo de bytes por carácter probablemente resultará en un problema para su aplicación.

Estas consideraciones implican que las cadenas de caracteres UTF-8 no deben "expandirse" en matrices de longitud fija antes del procesamiento, como se ha hecho a veces. En cambio, la programación debe realizarse directamente, utilizando funciones de cadena diseñadas específicamente para UTF-8.

David Spector
fuente
Nota: el párrafo sobre no usar una matriz de caracteres de ancho fijo es mi propia opinión. Estoy dispuesto a editar esta respuesta en respuesta a los comentarios.
David Spector