¿Cuáles son las diferencias entre UTF-8, UTF-16 y UTF-32?
Entiendo que todos almacenarán Unicode, y que cada uno usa un número diferente de bytes para representar un carácter. ¿Hay alguna ventaja en elegir uno sobre el otro?
¿Cuáles son las diferencias entre UTF-8, UTF-16 y UTF-32?
Entiendo que todos almacenarán Unicode, y que cada uno usa un número diferente de bytes para representar un carácter. ¿Hay alguna ventaja en elegir uno sobre el otro?
Respuestas:
UTF-8 tiene una ventaja en el caso en que los caracteres ASCII representan la mayoría de los caracteres en un bloque de texto, porque UTF-8 los codifica en 8 bits (como ASCII). También es ventajoso porque un archivo UTF-8 que contiene solo caracteres ASCII tiene la misma codificación que un archivo ASCII.
UTF-16 es mejor donde ASCII no es predominante, ya que utiliza 2 bytes por carácter, principalmente. UTF-8 comenzará a usar 3 o más bytes para los caracteres de orden superior donde UTF-16 permanece en solo 2 bytes para la mayoría de los caracteres.
UTF-32 cubrirá todos los caracteres posibles en 4 bytes. Esto lo hace bastante hinchado. No se me ocurre ninguna ventaja al usarlo.
En breve:
wchar_t
predeterminados de osx y linux a 4 bytes. gcc tiene una opción -fshort-wchar
que reduce el tamaño a 2 bytes, pero rompe la compatibilidad binaria con las bibliotecas estándar.
UTF-8 es variable de 1 a 4 bytes.
UTF-16 es variable 2 o 4 bytes.
UTF-32 tiene 4 bytes fijos .
Nota: UTF-8 puede tomar de 1 a 6 bytes con la última convención: https://lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html
Unicode define un único conjunto de caracteres enorme, asignando un valor entero único a cada símbolo gráfico (que es una simplificación importante, y no es realmente cierto, pero es lo suficientemente cerca para los fines de esta pregunta). UTF-8/16/32 son simplemente diferentes formas de codificar esto.
En resumen, UTF-32 usa valores de 32 bits para cada carácter. Eso les permite usar un código de ancho fijo para cada personaje.
UTF-16 usa 16 bits por defecto, pero eso solo le da 65k caracteres posibles, lo que no es lo suficientemente cercano para el conjunto completo de Unicode. Entonces, algunos caracteres usan pares de valores de 16 bits.
Y UTF-8 usa valores de 8 bits por defecto, lo que significa que los 127 primeros valores son caracteres de un byte de ancho fijo (el bit más significativo se usa para indicar que este es el comienzo de una secuencia de varios bytes, dejando 7 bits para el valor de carácter real). Todos los demás caracteres están codificados como secuencias de hasta 4 bytes (si la memoria sirve).
Y eso nos lleva a las ventajas. Cualquier carácter ASCII es directamente compatible con UTF-8, por lo que para actualizar aplicaciones heredadas, UTF-8 es una opción común y obvia. En casi todos los casos, también usará la menor cantidad de memoria. Por otro lado, no puedes hacer ninguna garantía sobre el ancho de un personaje. Puede tener 1, 2, 3 o 4 caracteres de ancho, lo que dificulta la manipulación de cadenas.
UTF-32 es opuesto, usa la mayor cantidad de memoria (cada carácter tiene un ancho fijo de 4 bytes), pero por otro lado, sabe que cada carácter tiene esta longitud precisa, por lo que la manipulación de cadenas se vuelve mucho más simple. Puede calcular el número de caracteres en una cadena simplemente a partir de la longitud en bytes de la cadena. No puedes hacer eso con UTF-8.
UTF-16 es un compromiso. Permite que la mayoría de los caracteres encajen en un valor de 16 bits de ancho fijo. Entonces, siempre que no tenga símbolos chinos, notas musicales u otros, puede suponer que cada carácter tiene 16 bits de ancho. Utiliza menos memoria que UTF-32. Pero de alguna manera es "lo peor de ambos mundos". Casi siempre usa más memoria que UTF-8, y todavía no evita el problema que afecta a UTF-8 (caracteres de longitud variable).
Finalmente, a menudo es útil ir con lo que la plataforma admite. Windows usa UTF-16 internamente, por lo que en Windows, esa es la opción obvia.
Linux varía un poco, pero generalmente usan UTF-8 para todo lo que es compatible con Unicode.
Respuesta breve: las tres codificaciones pueden codificar el mismo conjunto de caracteres, pero representan cada carácter como secuencias de bytes diferentes.
Unicode es un estándar y sobre UTF-x puede considerarse una implementación técnica para algunos fines prácticos:
Traté de dar una explicación simple en mi blog .
requiere 32 bits (4 bytes) para codificar cualquier carácter. Por ejemplo, para representar el punto de código de carácter "A" utilizando este esquema, deberá escribir 65 en un número binario de 32 bits:
00000000 00000000 00000000 01000001 (Big Endian)
Si observa más de cerca, notará que los siete bits más correctos son en realidad los mismos bits cuando se utiliza el esquema ASCII. Pero como UTF-32 es un esquema de ancho fijo , debemos adjuntar tres bytes adicionales. Lo que significa que si tenemos dos archivos que solo contienen el carácter "A", uno está codificado en ASCII y el otro está codificado en UTF-32, su tamaño será de 1 byte y 4 bytes correspondientes.
Mucha gente piensa que como UTF-32 usa un ancho fijo de 32 bits para representar un punto de código, UTF-16 es un ancho fijo de 16 bits. ¡INCORRECTO!
En UTF-16, el punto de código puede representarse en 16 bits o en 32 bits. Entonces, este esquema es un sistema de codificación de longitud variable. ¿Cuál es la ventaja sobre el UTF-32? Al menos para ASCII, el tamaño de los archivos no será 4 veces el original (pero aún dos veces), por lo que todavía no somos ASCII compatibles con versiones anteriores.
Dado que 7 bits son suficientes para representar el carácter "A", ahora podemos usar 2 bytes en lugar de 4 como el UTF-32. Se verá así:
00000000 01000001
Has acertado. En UTF-8, el punto de código puede representarse utilizando 32, 16, 24 u 8 bits, y como el sistema UTF-16, este también es un sistema de codificación de longitud variable.
Finalmente podemos representar "A" de la misma manera que lo representamos usando el sistema de codificación ASCII:
01001101
Considere la letra china "語": su codificación UTF-8 es:
11101000 10101010 10011110
Si bien su codificación UTF-16 es más corta:
10001010 10011110
Para comprender la representación y cómo se interpreta, visite la publicación original.
UTF-8 será el espacio más eficiente a menos que la mayoría de los caracteres sean del espacio de caracteres CJK (chino, japonés y coreano).
UTF-32 es mejor para acceso aleatorio por desplazamiento de caracteres en una matriz de bytes.
0xxxxxxx
en binario. Todos los caracteres de dos bytes comienzan 110xxxxx
con un segundo byte de 10xxxxxx
. Entonces, digamos que se pierde el primer carácter de un carácter de dos bytes. Tan pronto como vea 10xxxxxx
sin un precedente 110xxxxxx
, puede determinar con certeza si un byte se perdió o corrompió, y descarte ese carácter (o vuelva a solicitarlo de un servidor o lo que sea), y continúe hasta que vea un primer byte válido nuevamente .
Hice algunas pruebas para comparar el rendimiento de la base de datos entre UTF-8 y UTF-16 en MySQL.
En UTF-32, todos los caracteres están codificados con 32 bits. La ventaja es que puede calcular fácilmente la longitud de la cadena. La desventaja es que por cada carácter ASCII desperdicia tres bytes adicionales.
En los caracteres UTF-8 tienen una longitud variable, los caracteres ASCII se codifican en un byte (ocho bits), la mayoría de los caracteres especiales occidentales se codifican en dos bytes o tres bytes (por ejemplo, € es tres bytes), y pueden tomar más caracteres exóticos a cuatro bytes. La clara desventaja es que a priori no se puede calcular la longitud de la cadena. Pero se necesitan muchos menos bytes para codificar el texto del alfabeto latino (inglés), en comparación con UTF-32.
UTF-16 también es de longitud variable. Los caracteres se codifican en dos bytes o cuatro bytes. Realmente no veo el punto. Tiene la desventaja de ser de longitud variable, pero no tiene la ventaja de ahorrar tanto espacio como UTF-8.
De esos tres, claramente UTF-8 es el más extendido.
Según su entorno de desarrollo, es posible que ni siquiera tenga la opción de elegir qué codificación usará internamente su tipo de datos de cadena.
Pero para almacenar e intercambiar datos, siempre usaría UTF-8, si tiene la opción. Si tiene datos ASCII en su mayoría, esto le dará la menor cantidad de datos para transferir, al tiempo que podrá codificar todo. La optimización para el mínimo de E / S es el camino a seguir en las máquinas modernas.
Como se mencionó, la diferencia es principalmente el tamaño de las variables subyacentes, que en cada caso se hacen más grandes para permitir que se representen más caracteres.
Sin embargo, las fuentes, la codificación y las cosas son terriblemente complicadas (¿innecesariamente?), Por lo que se necesita un gran enlace para completar más detalles:
http://www.cs.tut.fi/~jkorpela/chars.html#ascii
No esperes entenderlo todo, pero si no quieres tener problemas más tarde, vale la pena aprender tanto como puedas, tan pronto como puedas (o simplemente conseguir que alguien más lo resuelva por ti).
Pablo.
En resumen, la única razón para usar UTF-16 o UTF-32 es para admitir scripts antiguos y no ingleses respectivamente.
Me preguntaba por qué alguien elegiría tener una codificación que no sea UTF-8 cuando obviamente es más eficiente para fines web / de programación.
Un error común: el número con sufijo NO es una indicación de su capacidad. Todos son compatibles con Unicode completo, solo que UTF-8 puede manejar ASCII con un solo byte, por lo que es MÁS eficiente / menos corruptible para la CPU y para Internet.
Algunas buenas lecturas: http://www.personal.psu.edu/ejp10/blogs/gotunicode/2007/10/which_utf_do_i_use.html y http://utf8everywhere.org