ñ es C3 B1: cuántos bytes ocupa un carácter en UTF-8
Convertir a hexadecimal UTF-8 significa pasar el texto a los bytes que el ordenador guarda de verdad y escribir cada byte con dos cifras hexadecimales, de 00 a FF. La letra ñ tiene el número Unicode (punto de código) U+00F1 y se guarda como los dos bytes C3 B1. Una A sin más es el byte 41, y el emoji 😀 son los cuatro bytes F0 9F 98 80. En sentido contrario, si pegas C3 B1 desde un log o un depurador, vuelves a obtener ñ.
Los dos cuadros de arriba se pueden editar, y el que modificas pasa a ser el original. La banda central escribe cada carácter con sus bytes debajo, como un subtítulo, y un color bajo cada byte indica si el carácter ocupa 1, 2, 3 o 4 bytes. Si pulsas un carácter, la lupa de bits muestra qué bits de su punto de código caen en cada byte UTF-8. El hexadecimal se puede escribir separado por espacios, seguido, como matriz 0x, con escapes \x o con codificación %, y al pegar se entienden los cinco.
Cuándo hace falta ver los bytes UTF-8
- Un log muestra \xc3\xb1 donde debería haber una letra: Python escribe los bytes fuera de ASCII como escapes \x, así que año guardado en UTF-8 aparece como b'a\xc3\xb1o'. Pega la línea entera en el cuadro hexadecimal, con las comillas y las letras sueltas, y el conversor la lee de nuevo como año.
- MySQL rechaza un emoji: utf8mb3 (antes llamado utf8) guarda como máximo 3 bytes por carácter, así que un carácter de 4 bytes como un emoji falla con el error 1366 y un mensaje parecido a Incorrect string value: '\xF0\x9F\x98\x80'. Si pegas esos bytes en el conversor, ves que 😀 es un solo carácter que necesita cuatro bytes.
- Dos textos que se ven iguales pero no coinciden: un espacio de no separación (C2 A0), un espacio de ancho cero (E2 80 8B) y la marca de orden de bytes al principio de un archivo (EF BB BF) no se ven en pantalla, pero sus bytes son distintos. La banda los etiqueta como NBSP, ZWSP y BOM.
- Un nombre de archivo con tilde no coincide: un volumen de Mac con HFS Plus guarda los nombres con una variante de la forma descompuesta (NFD), de modo que canción.txt puede llegar como una o, una tilde suelta y una n. Pasa de 12 a 13 bytes, y el conversor te dice qué resultaría al componerlo en NFC.
- Leer %C3%B1 en una dirección: una URL lleva el texto no ASCII convirtiéndolo antes a UTF-8 y escribiendo cada byte como % más dos cifras hexadecimales. Si pegas %61%C3%B1%6F, sale año.
- Meter una cadena en una matriz de bytes en el código: el firmware embebido y los protocolos de red suelen pedir 0x61, 0xC3, 0xB1, 0x6F. Elige el formato "Matriz 0x" y el conversor lo escribe de forma que puedes pegarlo directamente en el código fuente.
- La ñ o las tildes se convierten en letras raras: un texto como canción que aparece como canción, o como canci�n, indica que unos bytes UTF-8 se leyeron como Windows-1252, o al revés. Pon los bytes originales en el cuadro hexadecimal y el conversor muestra si son UTF-8 válido y cómo se leen en Windows-1252.
Cómo se usa
- Escribe texto en el cuadro de texto o pega bytes en el cuadro hexadecimal. La página se abre con un ejemplo, y los botones de arriba cargan caracteres ocultos, una tilde descompuesta, bytes \x de un log y bytes dañados.
- Las flechas entre los cuadros indican el sentido. Si editas el texto, la conversión va hacia abajo (codificar); si editas el hexadecimal, va hacia arriba (decodificar).
- Elige un formato hexadecimal y mayúsculas o minúsculas. Si ya hay hexadecimal en el cuadro, al cambiar el formato se reescriben los mismos bytes con el estilo nuevo.
- Pulsa un carácter de la banda, o mueve el cursor en un cuadro, y la lupa de bits muestra su punto de código, sus bytes en UTF-8, UTF-16 y Windows-1252 y su posición.
- Con "Copiar hexadecimal" o "Copiar texto" te llevas el resultado. El panel de abajo a la derecha compara cuántos bytes ocupa el mismo texto en UTF-16 y en Windows-1252.
Cómo reparte UTF-8 un carácter en bytes
UTF-8 escribe cada carácter de U+0000 a U+10FFFF con 1 a 4 bytes (RFC 3629). El primer byte empieza con unos bits que indican cuántos bytes tiene el carácter, y todos los bytes siguientes empiezan por 10. Por eso, mirando un solo byte, se sabe si empieza un carácter o continúa uno.
| Rango del punto de código | Bytes | Patrón de bits | Ejemplo |
|---|---|---|---|
| U+0000 a 007F | 1 | 0xxxxxxx | A → 41 |
| U+0080 a 07FF | 2 | 110xxxxx 10xxxxxx | ñ → C3 B1, Ω → CE A9 |
| U+0800 a FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx | € → E2 82 AC, 日 → E6 97 A5 |
| U+10000 a 10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 😀 → F0 9F 98 80 |
Hagámoslo a mano con €. U+20AC en binario es 0010 0000 1010 1100, dieciséis bits. El patrón de 3 bytes tiene sitio para 4 + 6 + 6 bits, así que se divide en 0010 / 000010 / 101100 y se coloca en 11100010, 10000010, 10101100. Esos tres bytes son E2, 82 y AC en hexadecimal. De U+0000 a 007F el byte es el propio punto de código, por lo que un texto formado solo por letras inglesas, cifras y signos de puntuación ASCII tiene los mismos bytes en ASCII y en UTF-8.
Las vocales con tilde, la ñ, la ü y los signos ¿ y ¡ están en la fila de 2 bytes, y por eso canción tiene 7 caracteres pero 8 bytes. Las comillas tipográficas, la raya y el signo del euro están en la fila de 3 bytes, y casi todos los emojis necesitan cuatro.
Bytes por carácter en UTF-8, UTF-16 y Windows-1252
| Carácter | Punto de código | UTF-8 | UTF-16 | Windows-1252 |
|---|---|---|---|---|
| A | U+0041 | 41 | 0041 | 41 |
| é | U+00E9 | C3 A9 | 00E9 | E9 |
| ñ | U+00F1 | C3 B1 | 00F1 | F1 |
| Ω | U+03A9 | CE A9 | 03A9 | no existe |
| € | U+20AC | E2 82 AC | 20AC | 80 |
| “ | U+201C | E2 80 9C | 201C | 93 |
| — | U+2014 | E2 80 94 | 2014 | 97 |
| 日 | U+65E5 | E6 97 A5 | 65E5 | no existe |
| あ | U+3042 | E3 81 82 | 3042 | no existe |
| 😀 | U+1F600 | F0 9F 98 80 | D83D DE00 | no existe |
| Espacio ideográfico | U+3000 | E3 80 80 | 3000 | no existe |
| Espacio de no separación | U+00A0 | C2 A0 | 00A0 | A0 |
| BOM | U+FEFF | EF BB BF | FEFF | no existe |
| ZWJ (unión) | U+200D | E2 80 8D | 200D | no existe |
Windows-1252 es una codificación de un byte, y sus bytes 80 a 9F contienen caracteres como el signo del euro (80), las comillas tipográficas (93 y 94) y la raya (97). En la tabla del navegador, las etiquetas latin1 e iso-8859-1 también se tratan como windows-1252, por eso una página declarada como "Latin-1" suele mostrar bien esos caracteres. Todo lo que queda fuera de sus 256 valores, como Ω, 日 o un emoji, simplemente no se puede guardar en ella.
El mismo texto, otra cantidad de bytes
| Texto | Caracteres visibles | Puntos de código | UTF-8 | UTF-16 | Windows-1252 |
|---|---|---|---|---|---|
| Hola | 4 | 4 | 4 | 8 | 4 |
| canción | 7 | 7 | 8 | 14 | 7 |
| ¡Sí! 5 € | 8 | 8 | 12 | 16 | 8 |
| 日本語 | 3 | 3 | 9 | 6 | 日 no existe |
| Hola 😀 | 6 | 6 | 9 | 14 | 😀 no existe |
| 👨👩👧 (familia) | 1 | 5 | 18 | 16 | no existe |
Con letras inglesas UTF-8 es lo más corto, y UTF-16 gasta siempre al menos dos bytes por unidad de código. La fila ¡Sí! 5 € muestra el coste de los signos del español: ocho caracteres ocupan 12 bytes en UTF-8, porque ¡, í y € no son ASCII, mientras que Windows-1252 los guarda en ocho. Esa economía de un byte explica por qué los archivos antiguos la usaban, y también por qué se rompen cuando los mismos bytes se leen como UTF-8. El emoji de familia parece un solo carácter en pantalla, pero son tres emojis de persona (4 bytes cada uno) unidos por dos ZWJ (3 bytes cada uno), y por eso ocupa 18 bytes.
Cinco formas de escribir el hexadecimal
| Formato | Aspecto | Uso habitual |
|---|---|---|
| Separado por espacios | 61 C3 B1 6F | Visores hexadecimales, bytes escritos en documentos y logs |
| Seguido | 61C3B16F | Resultado de bytes.hex() de Python, hashes y claves escritos de corrido |
| Matriz 0x | 0x61, 0xC3, 0xB1, 0x6F | Matrices de bytes en C, Java y JavaScript |
| Escapes \x | \x61\xC3\xB1\x6F | Representación de bytes de Python, cadenas de C, mensajes de error de MySQL |
| Codificación % | %61%C3%B1%6F | URL |
Al pegar no hace falta elegir formato. Espacios, tabuladores, saltos de línea, comas, dos puntos y guiones se tratan como separadores, de modo que el 61-C3-B1-6F que escribe BitConverter.ToString de .NET entra tal cual. En los formatos \x y % también se leen como bytes las letras y cifras sueltas escritas entre los escapes, y se quitan envoltorios como b'…', "…" o […]. La RFC 3986 recomienda mayúsculas en la codificación porcentual, pero mayúsculas y minúsculas son los mismos bytes.
// JavaScript: texto → hexadecimal UTF-8
[...new TextEncoder().encode('año')].map(b => b.toString(16).padStart(2, '0')).join(' '); // '61 c3 b1 6f'
# Python 3.8 o posterior: texto ↔ hexadecimal
'año'.encode('utf-8').hex(' ') # '61 c3 b1 6f'
bytes.fromhex('61 C3 B1 6F').decode('utf-8') # 'año' (los espacios se ignoran)
Bytes que no son UTF-8 válido
No toda secuencia de bytes es UTF-8. Un byte de continuación sin byte inicial, un carácter cortado por la mitad o un carácter escrito con más bytes de los necesarios dan UTF-8 no válido. La RFC 3629 prohíbe codificar el rango de sustitutos (U+D800 a DFFF) y avisa de que un decodificador no debe aceptar formas superlargas (overlong) como C0 80. Un navegador pone un carácter de reemplazo � (U+FFFD) por cada parte no válida; este conversor divide los bytes con la misma regla y marca en la banda los bytes erróneos y el motivo.
| Bytes | Motivo | Se muestra |
|---|---|---|
80 | 10xxxxxx continúa un carácter, pero no hay byte inicial | � |
FF | F5 a FF no aparecen nunca en UTF-8 | � |
C0 80 | U+0000 alargado a dos bytes, una forma superlarga (C0 y C1 están siempre prohibidos) | �� |
E0 80 80 | tras E0 solo puede venir A0 a BF (forma superlarga) | ��� |
ED A0 80 | el sustituto U+D800 (tras ED solo puede venir 80 a 9F) | ��� |
F4 90 80 80 | pasa de U+10FFFF (tras F4 solo puede venir 80 a 8F) | ���� |
E2 28 A1 | un carácter de 3 bytes cortado tras el primero; el 28 se lee aparte como "(" | �(� |
C3 | a la ó (C3 B3) le falta el segundo byte | � |
Como en las dos últimas filas, un carácter cortado se sustituye como un todo: los bytes que eran válidos hasta ese punto se agrupan en un único �. Unicode lo llama sustituir la "subparte máxima" (maximal subpart), y los mismos bytes dan el mismo número de � en un navegador y en este conversor. Mientras escribes en el cuadro hexadecimal, un último carácter a medias no se trata como error; el conversor te dice cuántos bytes faltan y solo lo juzga cuando sales del cuadro.
Deducir la codificación original a partir del texto estropeado
La mayoría del texto estropeado, llamado mojibake, viene de bytes guardados con una codificación y leídos con otra. La basura tiene sus costumbres, y su aspecto indica en qué sentido se cometió el error.
| Bytes originales | Leído mal como | Aparece |
|---|---|---|
UTF-8 'canción' 63 61 6E 63 69 C3 B3 6E | Windows-1252 | canción |
UTF-8 '¿Qué tal?' C2 BF 51 75 C3 A9 20 74 61 6C 3F | Windows-1252 | ¿Qué tal? |
UTF-8 '5 € — señor' 35 20 E2 82 AC 20 E2 80 94 20 73 65 C3 B1 6F 72 | Windows-1252 | 5 € — señor |
Windows-1252 'año' 61 F1 6F | UTF-8 | a�o |
Si una letra con tilde se convierte en à o  seguida de otro símbolo, y una raya o el euro se convierten en â seguida de €, ‚ o similares, se leyó UTF-8 como Windows-1252. Si en cambio las tildes y la ñ se convierten en �, lo más probable es que el texto fuera Windows-1252 leído como UTF-8, porque un byte como F1 o F3 seguido de una letra ASCII no es UTF-8 válido. Pon los bytes originales en el cuadro hexadecimal y el conversor prueba primero UTF-8; si falla, escribe debajo la lectura en Windows-1252. El ejemplo "Bytes dañados", 61 F1 6F 20 79 20 63 61 6E 63 69 F3 6E, es el texto "año y canción" guardado en Windows-1252.
Errores frecuentes
- Esperar un cambio de base numérica: si escribes 255 en el cuadro de texto, obtienes 32 35 35, los bytes de los caracteres de cifra 2, 5 y 5, no FF. Para cambiar la base de un número usa un conversor de bases.
- Mezclar puntos de código con bytes UTF-8: U+00F1 es el número de la ñ, mientras que C3 B1 es ese número guardado en UTF-8. Si pones U+00F1 o \u00F1 en el cuadro hexadecimal, aparece un aviso de que eso no son bytes.
- Tomar el hexadecimal por cifrado: el hexadecimal es solo una forma de escribir bytes, y cualquiera puede volver a convertirlo en texto. No lo uses para ocultar contraseñas ni datos personales.
- No saber si hay que quitar un EF BB BF inicial: es la marca de orden de bytes UTF-8 (U+FEFF), y al principio de un archivo sirve solo como firma. La FAQ de Unicode dice que los protocolos de bytes que esperan caracteres ASCII al principio deben evitarla, y también que un protocolo, como las convenciones de Microsoft para archivos .txt, puede exigirla. Comprueba qué hace el programa receptor antes de conservarla o quitarla.
- Esperar el salto de línea de Windows 0D 0A: los cuadros de entrada del navegador guardan el salto de línea como LF (0A). Un salto que escribes en el cuadro de texto es 0A; para inspeccionar un CR (0D), escribe 0D 0A en el cuadro hexadecimal.
- Contar igual caracteres y bytes: donde un límite de longitud cuenta bytes, "Hola, canción" cuesta 14 bytes para 13 caracteres, y los emojis cuestan más. Lee juntos los tres números sobre la banda: caracteres, puntos de código y bytes.
Límites
- La conversión se hace solo en tu navegador. El texto y los bytes que escribes no se envían a ningún servidor ni se guardan en la dirección ni en el almacenamiento.
- El texto se convierte hasta 100.000 posiciones UTF-16 cada vez y el hexadecimal hasta 1.200.000 posiciones, con los separadores. La banda dibuja solo los primeros 1.500 caracteres y bytes erróneos; el resto se sigue convirtiendo y copiando.
- La salida hexadecimal contiene solo bytes UTF-8. UTF-16 y Windows-1252 aparecen únicamente en la comparación de bytes y como valores por carácter en la lupa de bits.
- Los valores de Windows-1252 siguen la tabla WHATWG Encoding del navegador, así que un programa antiguo puede diferir en algunos caracteres.
- El texto nunca se normaliza automáticamente. El texto descompuesto (NFD) solo provoca un aviso, y cambia únicamente cuando pulsas "Componer en NFC".
- No se admiten archivos binarios arbitrarios como imágenes o archivos comprimidos. Para pasar un archivo a texto usa una herramienta de Base64.
- Al leer la codificación %, el + se queda como signo más (2B) y no como espacio. Para datos de formularios, donde + significa espacio, usa un codificador/decodificador de URL.
Fuentes
Base: las reglas de UTF-8 salen de la RFC 3629 y del capítulo 3 de The Unicode Standard 18.0, la codificación y decodificación del navegador y la tabla de Windows-1252 del estándar WHATWG Encoding, y los demás formatos y mensajes de los documentos siguientes, todos comprobados el 21 de octubre de 2026. Las reglas de bytes de UTF-8 no han cambiado desde la RFC 3629.
- 01RFC 3629 — UTF-8, a transformation format of ISO 10646U+0000 a 10FFFF con 1 a 4 bytes, sustitutos prohibidos, aviso sobre la forma superlarga C0 80, el BOM es EF BB BF
- 02The Unicode Standard 18.0 — Capítulo 3, ConformanceTabla 3-7 secuencias de bytes UTF-8 bien formadas, 3.9.6 sustitución de la subparte máxima por U+FFFD
- 03WHATWG — Encoding StandardDecodificador UTF-8, TextDecoder fatal e ignoreBOM, las etiquetas latin1 e iso-8859-1 equivalen a windows-1252
- 04Unicode — UTF-8, UTF-16, UTF-32 & BOM FAQUn BOM inicial es una firma; evitarlo en protocolos de bytes que esperan ASCII, aunque algunas convenciones lo exigen
- 05RFC 3986 — URI Generic Syntax2.1 codificación porcentual, se recomiendan mayúsculas; 2.5 convertir a UTF-8 y luego codificar con %
- 06MySQL 8.4 — The utf8mb3 Character SetMáximo 3 bytes por carácter, solo caracteres BMP (sin caracteres suplementarios), utf8 es un alias en desuso
- 07MySQL 8.4 — Server Error Message ReferenceError 1366 ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect %s value: '%s' for column
- 08Python 3 — Tipos integrados: bytesbytes.fromhex ignora los espacios ASCII, bytes.hex(sep) desde 3.8, bytes fuera de ASCII mostrados como escapes \x
- 09Microsoft Learn — BitConverter.ToStringPares hexadecimales unidos por guiones, por ejemplo "7F-2C-4A-00"
- 10MDN — TextEncoderCodifica siempre una cadena de JavaScript como UTF-8
- 11MDN — String: lengthCuenta unidades de código UTF-16, no caracteres
- 12Unicode Technical Standard #51 — Unicode EmojiRevisión 31 (Emoji 18.0), secuencias de emojis unidas con ZWJ
- 13Unicode Standard Annex #15 — Normalization FormsRevisión 58, NFD = descomposición canónica, NFC = descomposición canónica seguida de composición canónica
- 14Apple Technical Q&A QA1173 — Text Encodings in VFSHFS Plus (Mac OS Extended) usa una variante de la forma normal D para los nombres de archivo
Preguntas frecuentes
¿Cuántos bytes ocupa un carácter en UTF-8?
Depende del carácter. Las letras ASCII como A ocupan 1 byte (41), las letras con tilde como ñ ocupan 2 (C3 B1), caracteres como € y las comillas tipográficas ocupan 3 (E2 82 AC) y los emojis ocupan 4 (F0 9F 98 80). Por eso canción tiene 7 caracteres pero 8 bytes.
¿Cómo convierto \xc3\xb1 o %C3%B1 en texto?
Pégalo tal cual en el cuadro hexadecimal. El conversor lee escapes \x, codificación %, prefijos 0x y espacios, comas, dos puntos o guiones como separadores, y además quita un envoltorio como b'...' y lee las letras sueltas escritas entre los escapes. El cuadro de texto mostrará ñ.
¿Las mayúsculas y minúsculas del hexadecimal son valores distintos?
No. C3 y c3 son el mismo byte (195 en decimal). Puedes elegir si la salida va en mayúsculas o minúsculas, y la RFC 3986 recomienda mayúsculas en la codificación porcentual de las direcciones.
¿Qué hago si dice que unos bytes no se pueden leer como UTF-8?
O falta algún byte o el texto se guardó con otra codificación. El conversor indica cuál es el primer byte erróneo y por qué, y si los bytes se leen bien como Windows-1252 muestra esa lectura debajo. Por ejemplo, F1 solo no es UTF-8 válido, pero en Windows-1252 es ñ.
¿Por qué MySQL dice Incorrect string value: '\xF0\x9F\x98\x80'?
F0 9F 98 80 son los cuatro bytes UTF-8 del emoji 😀. El utf8mb3 de MySQL (antes llamado utf8) guarda como máximo 3 bytes por carácter, así que no puede contener un carácter de 4 bytes. Para guardar emojis, cambia el juego de caracteres de la columna a utf8mb4, que usa hasta 4 bytes.
¿Por qué un emoji aparece con 18 bytes?
Un emoji de familia como 👨👩👧 parece un solo carácter, pero son tres emojis de persona (4 bytes cada uno) unidos por dos uniones de ancho cero, ZWJ (3 bytes cada una). Eso da 5 puntos de código y 18 bytes en UTF-8. La banda muestra el ZWJ con su propia etiqueta.
¿Por qué canción se convierte en canción en algunas páginas?
La página guardó canción como UTF-8 (63 61 6E 63 69 C3 B3 6E) pero se leyó como Windows-1252, donde C3 se ve como à y B3 como ³. Pon los bytes originales en el cuadro hexadecimal para confirmar que son UTF-8 válido y declara después UTF-8 en la página o en el archivo.
¿Si escribo 255 sale FF?
No. Este conversor no cambia la base de un número, convierte caracteres en bytes UTF-8. El texto 255 son los caracteres de cifra 2, 5 y 5, que dan 32 35 35. Para pasar el número 255 a hexadecimal FF usa un conversor de bases.