UTF-8 es un estándar de codificación de caracteres utilizado para la comunicación electrónica. Definido por el estándar Unicode , el nombre deriva de Unicode Transformation Format – 8-bit . [1] Casi todas las páginas web se almacenan en UTF-8.
UTF-8 es capaz de codificar los 1.112.064 [2] valores escalares Unicode válidos utilizando una codificación de ancho variable de una a cuatro unidades de código de un byte (8 bits). Los puntos de código con valores numéricos más bajos, que tienden a aparecer con mayor frecuencia, se codifican utilizando menos bytes. Fue diseñado para la compatibilidad con versiones anteriores de ASCII : los primeros 128 caracteres de Unicode, que corresponden uno a uno con ASCII, se codifican utilizando un solo byte con el mismo valor binario que ASCII, de modo que un archivo codificado en UTF-8 que utilice solo esos caracteres es idéntico a un archivo ASCII. La mayoría del software diseñado para cualquier ASCII extendido puede leer y escribir UTF-8 (incluso en Microsoft Windows ) y esto da como resultado menos problemas de internacionalización que cualquier codificación de texto alternativa. [3] [4]
La Organización Internacional de Normalización (ISO) se propuso componer un conjunto de caracteres multibyte universal en 1989. El borrador de la norma ISO 10646 contenía un anexo no obligatorio llamado UTF-1 que proporcionaba una codificación de secuencia de bytes de sus puntos de código de 32 bits . Esta codificación no era satisfactoria por razones de rendimiento, entre otros problemas, y el mayor problema era probablemente que no tenía una separación clara entre ASCII y no ASCII: las nuevas herramientas UTF-1 serían compatibles con versiones anteriores con texto codificado en ASCII, pero el texto codificado en UTF-1 podría confundir al código existente que esperaba ASCII (o ASCII extendido ), porque podría contener bytes de continuación en el rango 0x21–0x7E que significaran algo más en ASCII, por ejemplo, 0x2F para /
, el separador de directorio de ruta de Unix .
En julio de 1992, el comité X/Open XoJIG buscaba una codificación mejor. Dave Prosser de Unix System Laboratories presentó una propuesta para una que tuviera características de implementación más rápidas e introdujo la mejora de que los caracteres ASCII de 7 bits solo se representarían a sí mismos; las secuencias multibyte solo incluirían bytes con el bit alto establecido. El nombre File System Safe UCS Transformation Format ( FSS-UTF ) [5] y la mayor parte del texto de esta propuesta se conservaron posteriormente en la especificación final. [6] [7] [8] En agosto de 1992, un representante de IBM X/Open circuló esta propuesta a las partes interesadas. Una modificación de Ken Thompson del grupo de sistema operativo Plan 9 en Bell Labs lo hizo autosincronizable , lo que permite que un lector comience en cualquier lugar y detecte inmediatamente los límites de los caracteres, a costa de ser algo menos eficiente en bits que la propuesta anterior. También abandonó el uso de sesgos que impedían codificaciones demasiado largas. [8] [9] El diseño de Thompson fue esbozado el 2 de septiembre de 1992, en un mantel individual en un restaurante de Nueva Jersey con Rob Pike . En los días siguientes, Pike y Thompson lo implementaron y actualizaron Plan 9 para usarlo en todo el sistema, [10] y luego comunicaron su éxito a X/Open, que lo aceptó como la especificación para FSS-UTF. [8]
UTF-8 se presentó oficialmente por primera vez en la conferencia USENIX en San Diego , del 25 al 29 de enero de 1993. [11] El Grupo de trabajo de ingeniería de Internet adoptó UTF-8 en su Política sobre conjuntos de caracteres e idiomas en RFC 2277 ( BCP 18) para futuros trabajos de estándares de Internet en enero de 1998, reemplazando conjuntos de caracteres de un solo byte como Latin-1 en RFC más antiguos. [12]
En noviembre de 2003, el RFC 3629 restringió UTF-8 para que coincidiera con las restricciones de la codificación de caracteres UTF-16 : al prohibir explícitamente los puntos de código correspondientes a los caracteres sustitutos alto y bajo, se eliminaron más del 3% de las secuencias de tres bytes, y al terminar en U+10FFFF se eliminaron más del 48% de las secuencias de cuatro bytes y todas las secuencias de cinco y seis bytes. [13]
UTF-8 codifica puntos de código en uno a cuatro bytes, según el valor del punto de código. En la siguiente tabla, los caracteres u a z se reemplazan por los bits del punto de código, desde las posiciones U+uvwxyz :
Los primeros 128 puntos de código (ASCII) necesitan 1 byte. Los siguientes 1.920 puntos de código necesitan dos bytes para codificarse, lo que cubre el resto de casi todos los alfabetos de escritura latina , y también las extensiones IPA , los alfabetos griego , cirílico , copto , armenio , hebreo , árabe , siríaco , thaana y n'ko , así como la combinación de marcas diacríticas . Se necesitan tres bytes para los 61.440 puntos de código restantes del plano multilingüe básico (BMP), que incluyen la mayoría de los caracteres chinos, japoneses y coreanos . Se necesitan cuatro bytes para los 1.048.576 puntos de código en los otros planos de Unicode , que incluyen emoji (símbolos pictográficos), caracteres CJK menos comunes , varias escrituras históricas y símbolos matemáticos .
Este es un código de prefijo y no es necesario leer más allá del último byte de un punto de código para decodificarlo. A diferencia de muchas codificaciones de texto de múltiples bytes anteriores, como Shift-JIS , se sincroniza automáticamente , por lo que es posible buscar cadenas o caracteres cortos y el comienzo de un punto de código se puede encontrar desde una posición aleatoria retrocediendo como máximo 3 bytes. Los valores elegidos para los bytes iniciales significan que al ordenar una lista de cadenas UTF-8, se colocan en el mismo orden que al ordenar cadenas UTF-32 .
El uso de una fila de la tabla anterior para codificar un punto de código menor que "Primer punto de código" (utilizando así más bytes de los necesarios) se denomina codificación demasiado larga . Estas son un problema de seguridad porque permiten que el mismo punto de código se codifique de múltiples maneras. Las codificaciones demasiado largas ( ../
por ejemplo, de) se han utilizado para eludir las validaciones de seguridad en productos de alto perfil, incluido el servidor web IIS de Microsoft [14] y el contenedor de servlets Tomcat de Apache. [15] Por lo tanto, las codificaciones demasiado largas deben considerarse un error y nunca deben decodificarse. UTF-8 modificado permite una codificación demasiado larga de U+0000 .
La siguiente tabla muestra el significado detallado de cada byte en una secuencia codificada en UTF-8.
No todas las secuencias de bytes son válidas en formato UTF-8. Un decodificador UTF-8 debe estar preparado para:
Muchos de los primeros decodificadores UTF-8 los decodificaban, ignorando los bits incorrectos. Un código UTF-8 no válido cuidadosamente diseñado podía hacer que se saltasen o creasen caracteres ASCII como NUL , barra o comillas, lo que daba lugar a vulnerabilidades de seguridad. También es habitual lanzar una excepción o truncar la cadena ante un error [16], pero esto convierte lo que de otro modo serían errores inofensivos (es decir, "archivo no encontrado") en una denegación de servicio ; por ejemplo, las primeras versiones de Python 3.0 salían inmediatamente si la línea de comandos o las variables de entorno contenían UTF-8 no válido. [17]
El RFC 3629 establece que "las implementaciones del algoritmo de decodificación DEBEN proteger contra la decodificación de secuencias no válidas". [18] El estándar Unicode requiere que los decodificadores: "... traten cualquier secuencia de unidad de código mal formada como una condición de error. Esto garantiza que no interpretará ni emitirá una secuencia de unidad de código mal formada". El estándar ahora recomienda reemplazar cada error con el carácter de reemplazo "�" (U+FFFD) y continuar con la decodificación.
Algunos decodificadores consideran la secuencia E1,A0,20 (un código truncado de 3 bytes seguido de un espacio) como un único error. Esto no es una buena idea, ya que una búsqueda de un carácter de espacio encontraría el que está oculto en el error. Desde Unicode 6 (octubre de 2010) [19], el estándar (capítulo 3) ha recomendado una "mejor práctica" en la que el error es un byte de continuación o termina en el primer byte que no está permitido, por lo que E1,A0,20 es un error de dos bytes seguido de un espacio. Esto significa que un error no tiene más de tres bytes de longitud y nunca contiene el comienzo de un carácter válido, y hay21.952 posibles errores diferentes. Técnicamente, esto hace que UTF-8 ya no sea un código de prefijo (hay que leer un byte más allá de algunos errores para saber si son un error), pero la búsqueda sigue funcionando si la cadena buscada no contiene ningún error.
Hacer que cada byte sea un error, en cuyo caso E1,A0,20 son dos errores seguidos de un espacio, también permite buscar una cadena válida. Esto significa que solo hay 128 errores diferentes, lo que hace que sea práctico almacenar los errores en la cadena de salida [20] o reemplazarlos con caracteres de una codificación heredada.
Solo un pequeño subconjunto de posibles cadenas de bytes son UTF-8 libres de errores: no pueden aparecer varios bytes; un byte con el bit alto establecido no puede estar solo; y en una cadena verdaderamente aleatoria, un byte con un bit alto establecido tiene solo una probabilidad de 1 ⁄ 15 de iniciar un carácter UTF-8 válido. Esto tiene la consecuencia (posiblemente no deseada) de hacer que sea fácil detectar si se usa accidentalmente una codificación de texto heredada en lugar de UTF-8, lo que hace que la conversión de un sistema a UTF-8 sea más fácil y evita la necesidad de requerir una marca de orden de bytes o cualquier otro metadato.
Desde RFC 3629 (noviembre de 2003), los sustitutos altos y bajos utilizados por UTF-16 ( U+D800 a U+DFFF ) no son valores Unicode legales, y sus codificaciones UTF-8 deben tratarse como una secuencia de bytes no válida. [18] Todas estas codificaciones comienzan con 0xED seguido de 0xA0 o superior. Esta regla a menudo se ignora ya que los sustitutos están permitidos en los nombres de archivo de Windows y esto significa que debe haber una forma de almacenarlos en una cadena. [21] UTF-8 que permite estas mitades sustitutas se ha llamado (informalmente)WTF-8 ,[22]mientras que otra variación que también codifica todos los caracteres que no son BMP como dos sustitutos (6 bytes en lugar de 4) se llama CESU-8 .
Si la marca de orden de bytes Unicode U+FEFF está al comienzo de un archivo UTF-8, los primeros tres bytes serán 0xEF , 0xBB , 0xBF .
El estándar Unicode no exige ni recomienda el uso de la BOM para UTF-8, pero advierte que puede encontrarse al comienzo de un archivo transcodificado a partir de otra codificación. [23] Si bien el texto ASCII codificado con UTF-8 es compatible con versiones anteriores de ASCII, esto no es así cuando se ignoran las recomendaciones del estándar Unicode y se agrega una BOM. Una BOM puede confundir al software que no está preparado para ello pero que, de otro modo, puede aceptar UTF-8, por ejemplo, lenguajes de programación que permiten bytes no ASCII en literales de cadena pero no al comienzo del archivo. Sin embargo, hubo y todavía hay software que siempre inserta una BOM al escribir UTF-8 y se niega a interpretar correctamente UTF-8 a menos que el primer carácter sea una BOM (o el archivo solo contenga ASCII). [24]
Durante mucho tiempo hubo una discusión considerable sobre si era mejor procesar texto en UTF-16 o en UTF-8.
La principal ventaja de UTF-16 es que la API de Windows requería que se utilizara para obtener acceso a todos los caracteres Unicode (esto se solucionó recientemente). Esto provocó que varias bibliotecas, como Qt, también utilizaran cadenas UTF-16, lo que propaga este requisito a plataformas que no son Windows.
En los primeros tiempos de Unicode no había caracteres mayores que U+FFFF y rara vez se utilizaban caracteres combinados , por lo que la codificación de 16 bits era de tamaño fijo. Esto hizo que el procesamiento de texto fuera más eficiente, aunque las ventajas no son tan grandes como los programadores novatos pueden imaginar. Todas estas ventajas se perdieron tan pronto como UTF-16 también pasó a tener ancho variable.
Los puntos de código U+0800 – U+FFFF ocupan 3 bytes en UTF-8, pero solo 2 en UTF-16. Esto llevó a la idea de que el texto en chino y otros idiomas ocuparía más espacio en UTF-8. Sin embargo, el texto solo es más grande si hay más de estos puntos de código que puntos de código ASCII de 1 byte, y esto rara vez sucede en los documentos del mundo real debido a los espacios, las nuevas líneas, los dígitos, la puntuación, las palabras en inglés y el marcado HTML.
UTF-8 tiene las ventajas de ser fácil de adaptar a cualquier sistema que pueda manejar un ASCII extendido , no tener problemas de orden de bytes y ocupar aproximadamente la mitad del espacio que ocuparía cualquier idioma que use principalmente letras latinas.
UTF-8 ha sido la codificación más común para la World Wide Web desde 2008. [26] A partir de octubre de 2024 [actualizar], el 98,3% de los sitios web encuestados utilizan UTF-8. [27] Aunque muchas páginas solo usan caracteres ASCII para mostrar contenido, muy pocos sitios web declaran ahora que su codificación es solo ASCII en lugar de UTF-8. [28] Más del 50% de los idiomas rastreados tienen un uso 100% de UTF-8.
Muchos estándares sólo admiten UTF-8, por ejemplo, el intercambio de JSON lo requiere (sin una marca de orden de bytes (BOM)). [29] UTF-8 también es la recomendación del WHATWG para las especificaciones HTML y DOM , y afirma que "la codificación UTF-8 es la codificación más apropiada para el intercambio de Unicode " [4] y el Consorcio de Correo de Internet recomienda que todos los programas de correo electrónico puedan mostrar y crear correo utilizando UTF-8. [30] [31] El Consorcio World Wide Web recomienda UTF-8 como la codificación predeterminada en XML y HTML (y no sólo usar UTF-8, también declararlo en metadatos), "incluso cuando todos los caracteres están en el rango ASCII ... El uso de codificaciones que no sean UTF-8 puede tener resultados inesperados". [32]
Muchos programas tienen la capacidad de leer y escribir UTF-8. Sin embargo, puede requerir que el usuario cambie las opciones de la configuración normal o que se requiera una marca de orden de bytes (BOM) como primer carácter para leer el archivo. Algunos ejemplos de programas que admiten UTF-8 son Microsoft Word , [33] [34] [35] Microsoft Excel (2016 y posteriores), [36] [37] Google Drive , LibreOffice y la mayoría de las bases de datos.
El software que "predeterminado" usa UTF-8 (lo que significa que lo escribe sin que el usuario cambie la configuración y lo lee sin una lista de materiales) se ha vuelto más común desde 2010. [38] El Bloc de notas de Windows , en todas las versiones de Windows compatibles actualmente, tiene como valor predeterminado escribir UTF-8 sin una lista de materiales (un cambio con respecto al Bloc de notas de Windows 7 ), lo que lo pone en línea con la mayoría de los demás editores de texto. [39] Algunos archivos del sistema en Windows 11 requieren UTF-8 [40] sin ningún requisito de una lista de materiales, y casi todos los archivos en macOS y Linux deben ser UTF-8 sin una lista de materiales. [ cita requerida ] Los lenguajes de programación que usan UTF-8 de manera predeterminada para E/S incluyen Ruby 3.0, [41] [42] R 4.2.2, [43] Raku y Java 18. [44] Aunque la versión actual de Python requiere una opción para leer/escribir UTF-8, [45] existen planes para hacer que UTF-8 sea el formato de E/S predeterminado en Python 3.15. [46] C++23 adopta UTF-8 como el único formato de archivo de código fuente portátil (sorprendentemente, antes no había ninguno). [47] open()
La compatibilidad con versiones anteriores es un impedimento grave para cambiar el código y las API que usan UTF-16 para usar UTF-8, pero esto está sucediendo. A partir de mayo de 2019 [actualizar], Microsoft agregó la capacidad para que una aplicación establezca UTF-8 como la "página de códigos" para la API de Windows, eliminando la necesidad de usar UTF-16; y más recientemente ha recomendado que los programadores usen UTF-8, [48] e incluso afirma que "UTF-16 [...] es una carga única que Windows coloca en el código que apunta a múltiples plataformas". [3] La primitiva de cadena predeterminada en Go , [49] Julia , Rust , Swift (desde la versión 5), [50] y PyPy [51] usa UTF-8 internamente en todos los casos. Python (desde la versión 3.3) usa UTF-8 internamente para las extensiones de la API de Python C [52] [53] y, a veces, para cadenas [52] [54] y se planea una versión futura de Python para almacenar cadenas como UTF-8 de forma predeterminada. [55] [56] Las versiones modernas de Microsoft Visual Studio usan UTF-8 internamente. [57] SQL Server 2019 de Microsoft agregó soporte para UTF-8, y su uso da como resultado un aumento de velocidad del 35% y una "reducción de casi el 50% en los requisitos de almacenamiento". [58]
Java utiliza internamente Modified UTF-8 (MUTF-8), en el que el carácter nulo U+0000 utiliza la codificación de dos bytes demasiado larga 0xC0 , 0x80 , en lugar de solo 0x00 . [59] Las cadenas UTF-8 modificadas nunca contienen ningún byte nulo real, pero pueden contener todos los puntos de código Unicode, incluido U+0000, [60] lo que permite que dichas cadenas (con un byte nulo añadido) sean procesadas por funciones de cadena terminadas en nulo tradicionales. Java lee y escribe UTF-8 normal en archivos y flujos, [61] pero utiliza Modified UTF-8 para la serialización de objetos , [62] [63] para la interfaz nativa de Java , [64] y para incrustar cadenas constantes en archivos de clase . [65] El formato dex definido por Dalvik también utiliza el mismo UTF-8 modificado para representar valores de cadena. [66] Tcl también utiliza el mismo UTF-8 modificado [67] que Java para la representación interna de datos Unicode, pero utiliza CESU-8 estricto para datos externos. Todas las implementaciones de UTF-8 modificado conocidas también tratan los pares sustitutos como en CESU-8 .
El lenguaje de programación Raku (anteriormente Perl 6) utiliza utf-8
codificación por defecto para E/S ( Perl 5 también la soporta); aunque esa elección en Raku también implica "normalización en Unicode NFC (forma de normalización canónica) . En algunos casos puede que quieras asegurarte de que no se haga ninguna normalización; para esto puedes usar utf8-c8
". [68] Esa variante UTF-8 Clean-8 , implementada por Raku, es un codificador/descodificador que preserva los bytes tal como están (incluso secuencias UTF-8 ilegales) y permite sintéticos de grafemas de forma normal. [69]
La versión 3 del lenguaje de programación Python trata cada byte de un flujo de bytes UTF-8 no válido como un error (ver también los cambios con el nuevo modo UTF-8 en Python 3.7 [70] ); esto da 128 posibles errores diferentes. Se han creado extensiones para permitir que cualquier secuencia de bytes que se asuma como UTF-8 se transforme sin pérdida a UTF-16 o UTF-32, traduciendo los 128 bytes de error posibles a puntos de código reservados y transformando esos puntos de código nuevamente a bytes de error para generar UTF-8. El enfoque más común es traducir los códigos a U+DC80...U+DCFF que son valores sustitutos bajos (finales) y, por lo tanto, UTF-16 "no válido", como se usa en el enfoque PEP 383 (o "surrogateescape") de Python . [20] Otra codificación llamada MirBSD OPTU-8/16 los convierte a U+EF80...U+EFFF en un Área de uso privado . [71] En cualquiera de los dos enfoques, el valor del byte se codifica en los ocho bits inferiores del punto de código de salida. Estas codificaciones son necesarias para que el UTF-8 no válido sobreviva a la traducción y luego vuelva del UTF-16 utilizado internamente por Python, y como los nombres de archivo de Unix pueden contener UTF-8 no válido, es necesario que esto funcione. [72]
El nombre oficial de la codificación es UTF-8
, la ortografía que se utiliza en todos los documentos del Consorcio Unicode. Se requiere el guión-menos y no se permiten espacios. Otros nombres utilizados son:
utf-8
se utilizan con frecuencia. [ cita requerida ]utf8
muchos otros alias. [73]csUTF8
como único alias, [74] que rara vez se utiliza.UTF-8N
significa UTF-8 sin una marca de orden de bytes (BOM), y en este caso UTF-8
puede implicar que hay una BOM. [75] [76]65001
[77] con el nombre simbólico CP_UTF8
en el código fuente.utf8mb4
, [78] mientras que utf8
y utf8mb3
hacen referencia a la variante obsoleta CESU-8 . [79]AL32UTF8
[80] significa UTF-8, mientras que UTF-8
significa CESU-8.18N
. [81]Existen varias definiciones actuales de UTF-8 en varios documentos de estándares:
Sustituyen las definiciones dadas en las siguientes obras obsoletas:
Todos son iguales en su mecánica general, y las principales diferencias están en cuestiones como el rango permitido de valores de puntos de código y el manejo seguro de entradas no válidas.
... en realidad, normalmente se asume que se trata de UTF-8, ya que es, con diferencia, la codificación más común.
Microsoft ahora guarda de forma predeterminada los archivos de texto nuevos como UTF-8 sin BOM, como se muestra a continuación.
Asegúrate de que LayoutModification.json use codificación UTF-8.
La representación UTF-8 se crea a pedido y se almacena en caché en el objeto Unicode.
Se eliminaron los miembros y
obsoletos
de la implementación C de objetos Unicode, según PEP 623.
wstr
wstr_length
Visual Studio utiliza UTF-8 como codificación de caracteres interna durante la conversión entre el conjunto de caracteres de origen y el conjunto de caracteres de ejecución.
InputStreamReader
yOutputStreamWriter
DataInput
yDataOutput
Anteriormente, en XP (y, no verificado, pero probablemente también en Vista), los bucles for simplemente no funcionaban mientras la página de códigos 65001 estaba activa