¿Diferencia entre UTF-8 y UTF-16?

137

¿Diferencia entre UTF-8 y UTF-16? ¿Por qué necesitamos estos?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
theJava
fuente
2
jon skeet tiene un buen artículo sobre codificación ... csharpindepth.com/Articles/General/Unicode.aspx
Mitch Wheat

Respuestas:

284

Creo que hay muchos buenos artículos sobre esto en la Web, pero aquí hay un breve resumen.

Tanto UTF-8 como UTF-16 son codificaciones de longitud variable. Sin embargo, en UTF-8 un carácter puede ocupar un mínimo de 8 bits, mientras que en UTF-16 la longitud del carácter comienza con 16 bits.

Principales profesionales de UTF-8:

  • Los caracteres ASCII básicos como dígitos, caracteres latinos sin acentos, etc. ocupan un byte que es idéntico a la representación US-ASCII. De esta manera, todas las cadenas US-ASCII se convierten en UTF-8 válidas, lo que proporciona una buena compatibilidad con versiones anteriores en muchos casos.
  • Sin bytes nulos, lo que permite utilizar cadenas terminadas en nulo, esto también introduce una gran cantidad de compatibilidad con versiones anteriores.
  • UTF-8 es independiente del orden de bytes, por lo que no tiene que preocuparse por el problema Big Endian / Little Endian.

Principales contras UTF-8:

  • Muchos caracteres comunes tienen una longitud diferente, lo que ralentiza la indexación por punto de código y el cálculo de un recuento de punto de código es terrible.
  • Aunque el orden de bytes no importa, a veces UTF-8 todavía tiene BOM (marca de orden de bytes) que sirve para notificar que el texto está codificado en UTF-8, y también rompe la compatibilidad con el software ASCII incluso si el texto solo contiene caracteres ASCII . Al software de Microsoft (como el Bloc de notas) le gusta especialmente agregar BOM a UTF-8.

Principales profesionales de UTF-16:

  • Caracteres BMP (plano multilingüe básico), incluidos el latín, el cirílico, la mayoría de los chinos (el PRC admitió algunos puntos de código fuera del BMP obligatorio), la mayoría de los japoneses se pueden representar con 2 bytes. Esto acelera la indexación y el cálculo del recuento de puntos de código en caso de que el texto no contenga caracteres suplementarios.
  • Incluso si el texto tiene caracteres suplementarios, todavía están representados por pares de valores de 16 bits, lo que significa que la longitud total sigue siendo divisible por dos y permite usar 16 bits charcomo el componente primitivo de la cadena.

Principales contras UTF-16:

  • Muchos bytes nulos en cadenas US-ASCII, lo que significa que no hay cadenas terminadas en nulo y mucha memoria desperdiciada.
  • Usarlo como una codificación de longitud fija "funciona principalmente" en muchos escenarios comunes (especialmente en EE. UU. / UE / países con alfabetos cirílicos / Israel / países árabes / Irán y muchos otros), lo que a menudo conduce a un soporte roto donde no lo hace. ¡Esto significa que los programadores deben ser conscientes de los pares sustitutos y manejarlos adecuadamente en los casos en que sea importante!
  • Es de longitud variable, por lo que contar o indexar puntos de código es costoso, aunque menor que UTF-8.

En general, UTF-16 suele ser mejor para la representación en memoria porque BE / LE es irrelevante allí (solo use el orden nativo) y la indexación es más rápida (simplemente no olvide manejar los pares sustitutos correctamente). UTF-8, por otro lado, es extremadamente bueno para archivos de texto y protocolos de red porque no hay problema BE / LE y la terminación nula a menudo es útil, así como la compatibilidad ASCII.

Sergei Tachenov
fuente
3
Falta solo la parte BE / LE en UTF16 :) UTF-8 tiene otra desventaja, puede generar una salida más larga que UTF16
mejor
44
Sí, me olvidé de BE / LE. Sin embargo, no es un gran problema, especialmente para el uso en memoria. UTF-8 generará una salida más larga solo si están involucrados caracteres de tres bytes, pero eso significa principalmente chino y japonés. Por otro lado, si el texto contiene muchos caracteres ASCII de EE. UU., Puede generar una salida más corta, por lo que si es una desventaja o no depende de una situación particular.
Sergei Tachenov
Ni siquiera pensé en mencionar el pro inmediato de utf-8, longitud más corta. Sobre la salida más larga de utf-8 fue 'mayo' por una razón, sin embargo, si el objetivo está muy al este, la codificación predeterminada debería ser utf-16. En cuanto al ejemplo md.update (text.getBytes ("UTF-8")); la codificación no importa ya que el hash es estable en ambos sentidos.
bestsss
La forma más rápida de convertir String a byte array es algo así, publicado como muestra
mejor
Dice que los caracteres tienen una longitud diferente en UTF-8, por lo que ralentiza la indexación y el cálculo de la longitud, pero dudo que los caracteres en UTF-16 también tengan una longitud diferente, ¿la indexación y el cálculo de la longitud de UTF-16 deberían ser más rápidos?
nicky_zs
19

Son simplemente esquemas diferentes para representar caracteres Unicode.

Ambos son de longitud variable: UTF-16 utiliza 2 bytes para todos los caracteres en el plano multilingüe básico (BMP) que contiene la mayoría de los caracteres de uso común.

UTF-8 utiliza entre 1 y 3 bytes para los caracteres en el BMP, hasta 4 para los caracteres en el rango actual de Unicode de U + 0000 a U + 1FFFFF, y es extensible hasta U + 7FFFFFFF si alguna vez es necesario ... pero notablemente todos los caracteres ASCII están representados en un solo byte cada uno.

A los efectos de un resumen del mensaje, no importa cuál elija, siempre y cuando todos los que intenten recrear el resumen utilicen la misma opción.

Consulte esta página para obtener más información sobre UTF-8 y Unicode.

(Tenga en cuenta que todos los caracteres Java son puntos de código UTF-16 dentro del BMP; para representar caracteres por encima de U + FFFF, debe usar pares sustitutos en Java).

Jon Skeet
fuente
5

Seguridad: use solo UTF-8

¿Diferencia entre UTF-8 y UTF-16? ¿Por qué necesitamos estos?

Ha habido al menos un par de vulnerabilidades de seguridad en las implementaciones de UTF-16 . Ver Wikipedia para más detalles .

WHATWG y W3C ahora han declarado que solo UTF-8 debe usarse en la Web.

Los problemas [de seguridad] descritos aquí desaparecen cuando se usa exclusivamente UTF-8, que es una de las muchas razones por las que ahora es la codificación obligatoria para todas las cosas.

Otros grupos dicen lo mismo.

Entonces, aunque UTF-16 puede continuar siendo utilizado internamente por algunos sistemas como Java y Windows, el poco uso de UTF-16 que haya visto en el pasado para archivos de datos, intercambio de datos y demás, probablemente se desvanecerá por completo.

Albahaca Bourque
fuente
4

Esto no está relacionado con UTF-8/16 (en general, aunque se convierte a UTF16 y la parte BE / LE se puede configurar con una sola línea), pero a continuación se muestra la forma más rápida de convertir String a byte []. Por ejemplo: bueno exactamente para el caso proporcionado (código hash). String.getBytes (enc) es relativamente lento.

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }
bestsss
fuente
-3

Una forma simple de diferenciar UTF-8 y UTF-16 es identificar elementos comunes entre ellos.

Además de compartir el mismo número Unicode para un personaje dado, cada uno tiene su propio formato.

Venkateswara Rao
fuente