¿Qué es Unicode, UTF-8, UTF-16?


395

¿Cuál es la base de Unicode y por qué la necesidad de UTF-8 o UTF-16? Investigué esto en Google y busqué aquí también, pero no me queda claro.

En VSS al hacer una comparación de archivos, a veces hay un mensaje que dice que los dos archivos tienen UTF diferentes. Por qué sería este el caso?

Por favor explique en términos simples.



55
Estas preguntas frecuentes del sitio web oficial de Unicode tienen algunas respuestas para usted.
Nemanja Trifunovic

44
@John: es una muy buena introducción, pero no es la fuente principal: omite algunos detalles (¡lo cual está bien para una descripción general / introducción!)
Joachim Sauer

55
El artículo es excelente, pero tiene varios errores y representa UTF-8 en una luz algo conservadora. Sugiero leer utf8everywhere.org como suplemento.
Pavel Radzivilovsky

2
Eche un vistazo a este sitio web: utf8everywhere.org
Vertexwahn

Respuestas:


550

¿Por qué necesitamos Unicode?

En los primeros días (no demasiado), todo lo que existía era ASCII. Esto estaba bien, ya que todo lo que se necesitaría eran unos pocos caracteres de control, puntuación, números y letras como los de esta oración. Desafortunadamente, el extraño mundo actual de intercomunicación global y redes sociales no estaba previsto, y no es demasiado inusual ver inglés, العربية, 汉语, עִבְרִית, ελληνικά, y ភាសាខ្មែរ en el mismo documento (espero no romper ninguno navegadores)

Pero por el bien de la discusión, digamos que Joe Average es un desarrollador de software. Insiste en que solo necesitará inglés y, como tal, solo quiere usar ASCII. Esto podría estar bien para Joe el usuario , pero no está bien para Joe el desarrollador de software . Aproximadamente la mitad del mundo usa caracteres no latinos y el uso de ASCII es posiblemente desconsiderado con estas personas, y además de eso, está cerrando su software a una economía grande y en crecimiento.

Por lo tanto, se necesita un conjunto de caracteres que incluya todos los idiomas. Así llegó Unicode. Asigna a cada carácter un número único llamado punto de código . Una ventaja de Unicode sobre otros conjuntos posibles es que los primeros 256 puntos de código son idénticos a ISO-8859-1 y, por lo tanto, también a ASCII. Además, la gran mayoría de los caracteres de uso común son representables por solo dos bytes, en una región llamada Plano Bilingüe Multilingüe (BMP) . Ahora se necesita una codificación de caracteres para acceder a este conjunto de caracteres, y como pregunta la pregunta, me concentraré en UTF-8 y UTF-16.

Consideraciones de memoria

Entonces, ¿cuántos bytes dan acceso a qué caracteres en estas codificaciones?

  • UTF-8:
    • 1 byte: ASCII estándar
    • 2 bytes: árabe, hebreo, la mayoría de las escrituras europeas (más notablemente excluyendo georgiano )
    • 3 bytes: BMP
    • 4 bytes: todos los caracteres Unicode
  • UTF-16:
    • 2 bytes: BMP
    • 4 bytes: todos los caracteres Unicode

Vale la pena mencionar ahora que los caracteres que no están en el BMP incluyen scripts antiguos, símbolos matemáticos, símbolos musicales y caracteres chinos / japoneses / coreanos (CJK) más raros .

Si trabajará principalmente con caracteres ASCII, entonces UTF-8 es ciertamente más eficiente en memoria. Sin embargo, si está trabajando principalmente con scripts no europeos, el uso de UTF-8 podría ser hasta 1.5 veces menos eficiente en memoria que UTF-16. Cuando se trata de grandes cantidades de texto, como páginas web grandes o documentos largos, esto podría afectar el rendimiento.

Conceptos básicos de codificación

Nota: Si sabe cómo se codifican UTF-8 y UTF-16, pase a la siguiente sección para obtener aplicaciones prácticas.

  • UTF-8: para los caracteres ASCII estándar (0-127), los códigos UTF-8 son idénticos. Esto hace que UTF-8 sea ideal si se requiere compatibilidad con el texto ASCII existente. Otros caracteres requieren entre 2 y 4 bytes. Esto se hace reservando algunos bits en cada uno de estos bytes para indicar que es parte de un carácter de varios bytes. En particular, el primer bit de cada byte es 1evitar el choque con los caracteres ASCII.
  • UTF-16: para caracteres BMP válidos, la representación UTF-16 es simplemente su punto de código. Sin embargo, para los caracteres que no son BMP, UTF-16 introduce pares sustitutos . En este caso, una combinación de dos porciones de dos bytes se correlaciona con un carácter no BMP. Estas porciones de dos bytes provienen del rango numérico BMP, pero el estándar Unicode garantiza que no son válidas como caracteres BMP. Además, dado que UTF-16 tiene dos bytes como su unidad básica, se ve afectado por la endianidad . Para compensar, se puede colocar una marca de orden de bytes reservada al comienzo de un flujo de datos que indica endianness. Por lo tanto, si está leyendo la entrada UTF-16, y no se especifica endianness, debe verificar esto.

Como se puede ver, UTF-8 y UTF-16 no son en absoluto compatibles entre sí. Entonces, si está haciendo E / S, ¡asegúrese de saber qué codificación está usando! Para obtener más detalles sobre estas codificaciones, consulte las preguntas frecuentes de UTF .

Consideraciones prácticas de programación

Tipos de datos de caracteres y cadenas: ¿cómo se codifican en el lenguaje de programación? Si son bytes sin procesar, en el momento en que intente generar caracteres que no sean ASCII, puede encontrarse con algunos problemas. Además, incluso si el tipo de carácter se basa en un UTF, eso no significa que las cadenas sean UTF adecuadas. Pueden permitir secuencias de bytes que son ilegales. En general, tendrá que usar una biblioteca que admita UTF, como ICU para C, C ++ y Java. En cualquier caso, si desea ingresar / emitir algo que no sea la codificación predeterminada, primero deberá convertirla.

Codificaciones recomendadas / predeterminadas / dominantes: cuando se le da la opción de elegir qué UTF usar, generalmente es mejor seguir los estándares recomendados para el entorno en el que está trabajando. Por ejemplo, UTF-8 es dominante en la web, y desde HTML5, ha sido la codificación recomendada . Por el contrario, los entornos .NET y Java se basan en un tipo de caracteres UTF-16. Confusamente (e incorrectamente), a menudo se hacen referencias a la "codificación Unicode", que generalmente se refiere a la codificación UTF dominante en un entorno dado.

Soporte de biblioteca: las bibliotecas que está utilizando admiten algún tipo de codificación. ¿Cúal? ¿Apoyan los casos de esquina? Dado que la necesidad es la madre de la invención, las bibliotecas UTF-8 generalmente admitirán caracteres de 4 bytes correctamente, ya que los caracteres de 1, 2 e incluso 3 bytes pueden aparecer con frecuencia. Sin embargo, no todas las bibliotecas UTF-16 supuestas admiten pares sustitutos correctamente, ya que ocurren muy raramente.

Contando caracteres: existen caracteres combinados en Unicode. Por ejemplo, el punto de código U + 006E (n) y U + 0303 (una tilde combinada) forma ñ, pero el punto de código U + 00F1 forma ñ. Deben verse idénticos, pero un algoritmo de conteo simple devolverá 2 para el primer ejemplo, 1 para el último. Esto no es necesariamente incorrecto, pero tampoco puede ser el resultado deseado.

Comparando para igualdad: A, А y Α se ven iguales, pero son latinos, cirílicos y griegos respectivamente. También tiene casos como C y Ⅽ, uno es una letra y el otro un número romano. Además, también tenemos los caracteres combinados a tener en cuenta. Para más información ver Caracteres duplicados en Unicode .

Pares sustitutos: estos aparecen con bastante frecuencia en SO, por lo que solo proporcionaré algunos enlaces de ejemplo:

¿Otros?:


11
Excelente respuesta, grandes posibilidades para la recompensa ;-) Personalmente, agregaría que algunos argumentan que UTF-8 es la codificación universal de caracteres , pero sé que esa es una opinión que no necesariamente es compartida por todos.
Joachim Sauer

3
Todavía es demasiado técnico para mí en esta etapa. ¿Cómo se almacena la palabra hola en una computadora en UTF-8 y UTF-16?
Nombre Apellido

1
¿Podría ampliar más sobre por qué, por ejemplo, el BMP toma 3 bytes en UTF-8? Pensé que dado que su valor máximo es 0xFFFF (16 bits), solo tomaría 2 bytes para acceder.
marca el

2
@mark Algunos bits están reservados para fines de codificación. Para un punto de código que toma 2 bytes en UTF-8, hay 5 bits reservados, dejando solo 11 bits para seleccionar un punto de código. U + 07FF termina siendo el punto de código más alto representable en 2 bytes.
DPenner1

1
Por cierto, ASCII solo define 128 puntos de código, usando solo 7 bits para la representación. Es ISO-8859-1 / ISO-8859-15 que define 256 puntos de código y utiliza 8 bits para la representación. Los primeros 128 puntos de código en todos estos 3 son los mismos.
Tuxdude

67
  • Unicode
    • es un conjunto de personajes utilizados en todo el mundo
  • UTF-8
    • una codificación de caracteres capaz de codificar todos los caracteres posibles (llamados puntos de código) en Unicode.
    • la unidad de código es de 8 bits
    • use de una a cuatro unidades de código para codificar Unicode
    • 00100100 para " $ " (uno de 8 bits); 11000010 10100010 para " ¢ " (dos de 8 bits); 11100010 10000010 10101100 para " " (tres de 8 bits)
  • UTF-16
    • otra codificación de caracteres
    • la unidad de código es de 16 bits
    • use una o dos unidades de código para codificar Unicode
    • 00000000 00100100 para " $ " (uno de 16 bits); 11011000 01010010 11011111 01100010 para " 𤭢 " (dos de 16 bits)

1
Corto y preciso
Aritra Chatterjee

30

Unicode es un estándar bastante complejo. ¡No tengas demasiado miedo, pero prepárate para un poco de trabajo! [2]

Debido a que siempre se necesita un recurso creíble, pero el informe oficial es masivo, sugiero leer lo siguiente:

  1. El mínimo absoluto que todo desarrollador de software debe saber absolutamente, positivamente sobre los conjuntos de caracteres y Unicode (¡sin excusas!) Una introducción de Joel Spolsky, CEO de Stack Exchange.
  2. ¡A BMP y más allá! Un tutorial de Eric Muller, Director Técnico y vicepresidente más tarde, en The Unicode Consortium. (primeras 20 diapositivas y ya está)

Una breve explicación:

Las computadoras leen bytes y las personas leen caracteres, entonces usamos estándares de codificación para asignar caracteres a bytes. ASCII fue el primer estándar ampliamente utilizado, pero cubre solo latín (7 bits / carácter puede representar 128 caracteres diferentes). Unicode es un estándar con el objetivo de cubrir todos los caracteres posibles en el mundo (puede contener hasta 1,114,112 caracteres, lo que significa un máximo de 21 bits / carácter. Unicode 8.0 actual especifica 120,737 caracteres en total, y eso es todo).

La principal diferencia es que un carácter ASCII puede caber en un byte (8 bits), pero la mayoría de los caracteres Unicode no. Por lo tanto, se utilizan formas / esquemas de codificación (como UTF-8 y UTF-16), y el modelo de caracteres es el siguiente:

Cada personaje tiene una posición enumerada de 0 a 1,114,111 (hexadecimal: 0-10FFFF) llamado punto de código .
Un formulario de codificación asigna un punto de código a una secuencia de unidad de código. Una unidad de código es la forma en que desea que los caracteres se organicen en la memoria, unidades de 8 bits, unidades de 16 bits, etc. UTF-8 usa 1 a 4 unidades de 8 bits, y UTF-16 usa 1 o 2 unidades de 16 bits, para cubrir todo el Unicode de 21 bits como máximo. Las unidades usan prefijos para que los límites de los caracteres se puedan detectar, y más unidades significan más prefijos que ocupan bits. Entonces, aunque UTF-8 usa 1 byte para el script latino, necesita 3 bytes para scripts posteriores dentro del Plano Multilingüe Básico, mientras que UTF-16 usa 2 bytes para todos estos. Y esa es su principal diferencia.
Por último, un esquema de codificación (como UTF-16BE o UTF-16LE) asigna (serializa) una secuencia de unidad de código a una secuencia de bytes.

carácter:
punto de código π :
formas de codificación U + 03C0 (unidades de código):
      UTF-8: CF 80
      UTF-16:
esquemas de codificación 03C0 (bytes):
      UTF-8: CF 80
      UTF-16BE: 03 C0
      UTF-16LE: C0 03

Consejo: un dígito hexadecimal representa 4 bits, por lo que un número hexadecimal de dos dígitos representa un byte.
También eche un vistazo a los mapas planos en Wikipedia para tener una idea del diseño del juego de caracteres.


19

Originalmente, Unicode estaba destinado a tener una codificación de ancho fijo de 16 bits (UCS-2). Los primeros usuarios de Unicode, como Java y Windows NT, construyeron sus bibliotecas en torno a cadenas de 16 bits.

Más tarde, el alcance de Unicode se amplió para incluir caracteres históricos, lo que requeriría más de los 65.536 puntos de código que admitiría una codificación de 16 bits. Para permitir que los caracteres adicionales se representaran en plataformas que habían usado UCS-2, se introdujo la codificación UTF-16. Utiliza "pares sustitutos" para representar personajes en los planos suplementarios.

Mientras tanto, una gran cantidad de software y protocolos de red más antiguos usaban cadenas de 8 bits. UTF-8 fue creado para que estos sistemas pudieran soportar Unicode sin tener que usar caracteres anchos. Es compatible con versiones anteriores de ASCII de 7 bits.


3
Vale la pena señalar que Microsoft todavía se refiere a UTF-16 como Unicode, lo que aumenta la confusión. Los dos no son lo mismo.
Mark Ransom

15

Este artículo explica todos los detalles http://kunststube.net/encoding/

ESCRIBIR AL BUFFER

Si escribe en un búfer de 4 bytes, símbolo con codificación UTF8, su binario se verá así:

00000000 11100011 10000001 10000010

si escribe en un búfer de 4 bytes, símbolo con codificación UTF16, su binario se verá así:

00000000 00000000 00110000 01000010

Como puede ver, dependiendo del idioma que usaría en su contenido, esto afectará su memoria en consecuencia.

Por ejemplo, para este símbolo en particular: la codificación UTF16 es más eficiente ya que tenemos 2 bytes de repuesto para usar para el siguiente símbolo. Pero eso no significa que deba usar UTF16 para el alfabeto japonés.

LEYENDO DEL BUFFER

Ahora, si desea leer los bytes anteriores, debe saber en qué codificación se escribió y decodificar de nuevo correctamente.

Por ejemplo, si decodifica esto: 00000000 11100011 10000001 10000010 en codificación UTF16, terminará sin

Nota: La codificación y Unicode son dos cosas diferentes. Unicode es la gran (tabla) con cada símbolo asignado a un punto de código único. Por ejemplo, el símbolo (letra) tiene un (punto de código) : 30 42 (hexadecimal). La codificación, por otro lado, es un algoritmo que convierte los símbolos de una manera más apropiada, cuando se almacena en el hardware.

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.

ingrese la descripción de la imagen aquí


12

Unicode es un estándar que asigna los caracteres en todos los idiomas a un valor numérico particular llamado Puntos de código . La razón por la que hace esto es que permite diferentes codificaciones posibles utilizando el mismo conjunto de puntos de código.

UTF-8 y UTF-16 son dos de esas codificaciones. Toman puntos de código como entrada y los codifica usando una fórmula bien definida para producir la cadena codificada.

Elegir una codificación particular depende de sus requisitos. Las diferentes codificaciones tienen diferentes requisitos de memoria y, dependiendo de los caracteres con los que se tratará, debe elegir la codificación que utiliza la menor cantidad de secuencias de bytes para codificar esos caracteres.

Para obtener detalles más detallados sobre Unicode, UTF-8 y UTF-16, puede consultar este artículo,

Lo que todo programador debe saber sobre Unicode


9

¿Por qué unicode? Porque ASCII tiene solo 127 caracteres. Los de 128 a 255 difieren en los diferentes países, por eso hay páginas de códigos. Entonces dijeron que tengamos hasta 1114111 caracteres. Entonces, ¿cómo se almacena el punto de código más alto? Deberá almacenarlo con 21 bits, por lo que usará un DWORD que tenga 32 bits con 11 bits desperdiciados. Entonces, si usa un DWORD para almacenar un carácter unicode, es la forma más fácil porque el valor en su DWORD coincide exactamente con el punto de código. Pero las matrices DWORD son, por supuesto, más grandes que las matrices WORD y, por supuesto, incluso más grandes que las matrices BYTE. Es por eso que no solo hay utf-32, sino también utf-16. Pero utf-16 significa una secuencia de WORD, y una WORD tiene 16 bits, entonces, ¿cómo puede encajar el punto de código más alto 1114111 en una WORD? ¡No puede! Así que pusieron todo lo superior a 65535 en un DWORD que llaman un par sustituto. Tal par sustituto son dos PALABRAS y se pueden detectar observando los primeros 6 bits. Entonces, ¿qué pasa con utf-8? Es una matriz de bytes o una secuencia de bytes, pero ¿cómo puede encajar el punto de código más alto 1114111 en un byte? ¡No puede! Bien, entonces pusieron también un DWORD ¿verdad? O posiblemente una PALABRA, ¿verdad? ¡Casi cierto! Inventaron secuencias utf-8, lo que significa que cada punto de código superior a 127 debe codificarse en una secuencia de 2 bytes, 3 bytes o 4 bytes. ¡Guauu! Pero, ¿cómo podemos detectar tales secuencias? Bueno, todo hasta 127 es ASCII y es un solo byte. Lo que comienza con 110 es una secuencia de dos bytes, lo que comienza con 1110 es una secuencia de tres bytes y lo que comienza con 11110 es una secuencia de cuatro bytes. Los bits restantes de estos llamados "startbytes" pertenecen al punto de código. Ahora, dependiendo de la secuencia, deben seguir los siguientes bytes. Un siguiente byte comienza con 10, los bits restantes son 6 bits de bits de carga útil y pertenecen al punto de código. Concatene los bits de carga útil del byte de inicio y los siguientes byte / sy obtendrá el punto de código. Esa es toda la magia de utf-8.


3
utf-8 ejemplo de signo € (Euro) descodificado en la secuencia utf-8 de 3 bytes: E2 = 11100010 82 = 10000010 AC = 10101100 Como puede ver, E2 comienza con 1110, así que esta es una secuencia de tres bytes Como puede ver , 82, así como AC comienza con 10, por lo que estos son los siguientes bytes Ahora concatenamos los "bits de carga útil": 0010 + 000010 + 101100 = 10000010101100 que es decimal 8364 Entonces 8364 debe ser el punto de código para el signo € (Euro).
Brighty

5

ASCII: el software asigna solo un byte de 8 bits en la memoria para un carácter dado. Funciona bien para caracteres en inglés y adoptados (palabras de préstamo como fachada) ya que sus valores decimales correspondientes caen por debajo de 128 en el valor decimal. Programa de ejemplo C.

UTF-8: el software asigna de 1 a 4 bytes de 8 bits variables para un carácter dado. ¿Qué significa aquí por variable? Digamos que está enviando el carácter 'A' a través de sus páginas HTML en el navegador (HTML es UTF-8), el valor decimal correspondiente de A es 65, cuando lo convierte en decimal se convierte en 01000010. Esto requiere solo 1 bytes , 1 byte de memoria se asigna incluso para caracteres ingleses especiales adoptados como 'ç' en una palabra de fachada. Sin embargo, cuando desea almacenar caracteres europeos, requiere 2 bytes, por lo que necesita UTF-8. Sin embargo, cuando elige caracteres asiáticos, necesita un mínimo de 2 bytes y un máximo de 4 bytes. Del mismo modo, los Emoji requieren de 3 a 4 bytes. UTF-8 resolverá todas sus necesidades.

UTF-16 asignará un mínimo de 2 bytes y un máximo de 4 bytes por carácter, no asignará 1 o 3 bytes. Cada carácter está representado en 16 bits o 32 bits.

Entonces, ¿por qué existe UTF-16? Originalmente, Unicode era de 16 bits, no de 8 bits. Java adoptó la versión original de UTF-16.

En pocas palabras, no necesita UTF-16 en ninguna parte a menos que ya haya sido adoptado por el idioma o la plataforma en la que está trabajando.

El programa Java invocado por los navegadores web usa UTF-16 pero el navegador web envía caracteres usando UTF-8.


"No necesita UTF-16 en ninguna parte a menos que ya haya sido adoptado por el lenguaje o la plataforma": este es un buen punto, pero aquí hay una lista no inclusiva: JavaScript, Java, .NET, SQL NCHAR, SQL NVARCHAR , VB4, VB5, VB6, VBA, VBScript, NTFS, API de Windows ...
Tom Blodget

2

UTF son las siglas de Unicode Transformation Format. Básicamente, en el mundo actual hay scripts escritos en cientos de otros idiomas, formatos que no están cubiertos por el ASCII básico utilizado anteriormente. Por lo tanto, UTF entró en existencia.

UTF-8 tiene capacidades de codificación de caracteres y su unidad de código es de 8 bits, mientras que para UTF-16 es de 16 bits.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.