Las codificaciones de texto explicadas: UTF-8, Base64 y codificación URL

Actualizado:

Los ordenadores guardan y envían bytes, no letras. Cada vez que un texto se guarda, se envía o se pone en una dirección web, algo tiene que decidir qué bytes representan qué caracteres, y a veces hay que reescribir los propios bytes para que lleguen intactos. Tres codificaciones hacen la mayor parte de ese trabajo: UTF-8 convierte caracteres en bytes, Base64 convierte cualquier byte en letras y cifras corrientes, y la codificación por porcentaje hace que un texto sea seguro dentro de una URL.

Esta última parte de la serie explica cada una con ejemplos que se pueden comprobar byte a byte, y las relaciona con los problemas vistos en las partes sobre JSON y CSV: la marca de orden de bytes y las tildes que se convierten en ã.

Caracteres, puntos de código y bytes

Unicode asigna a cada carácter un número, llamado punto de código y escrito como U+ seguido de cifras hexadecimales: A es U+0041, é es U+00E9, € es U+20AC y el emoji 😀 es U+1F600. El rango va de U+0000 a U+10FFFF. Una codificación decide cómo se guardan esos números en bytes.

UTF-8, definido en el RFC 3629 (estándar de Internet desde noviembre de 2003), usa de uno a cuatro bytes por carácter. Los 128 caracteres ASCII conservan su único byte, de modo que un texto en inglés sin acentos es idéntico en ASCII y en UTF-8; los demás caracteres ocupan dos, tres o cuatro bytes:

UTF-8 es hoy la opción por defecto casi en todas partes: W3Techs lo encontró en el 99,1% de los sitios web cuya codificación pudo identificar en octubre de 2026. Dentro de los programas siguen existiendo otras codificaciones. Las cadenas de JavaScript, por ejemplo, se guardan en UTF-16, en unidades de 16 bits, y MDN señala que un carácter por encima de U+FFFF ocupa dos. Por eso el mismo emoji cuenta como 1 carácter en pantalla, 2 en la longitud de JavaScript y 4 bytes en UTF-8, y por eso los límites medidos en caracteres y en bytes casi nunca coinciden.

La marca de orden de bytes

La marca de orden de bytes (BOM), U+FEFF, puede ir al principio de un archivo. En UTF-8 son siempre los tres bytes EF BB BF. UTF-8 no tiene orden de bytes que marcar, así que ahí solo sirve como firma que indica que el archivo es UTF-8. El Consorcio Unicode desaconseja usarla cuando un protocolo o un programa espera caracteres concretos al principio del archivo.

Las dos partes anteriores de la serie se la encuentran desde lados opuestos. Un JSON enviado por la red no debe empezar con ella, y JSON.parse de JavaScript rechaza el texto que la lleva. Excel, en cambio, la necesita para abrir bien un CSV en UTF-8 con doble clic. Ponerla o no depende del programa que vaya a leer el archivo.

Base64: cualquier byte como texto

Algunos sitios solo aceptan texto: el cuerpo de un correo, una cadena JSON, un atributo HTML. Base64, especificado en el RFC 4648 (octubre de 2006), permite que cualquier byte, incluida una imagen o un PDF, pase por ellos. Toma la entrada de tres en tres bytes (24 bits) y escribe cada grupo como cuatro caracteres de un alfabeto de 64: A–Z, a–z, 0–9, + y /. Cuando el último grupo se queda corto, = lo completa. Estos son los vectores de prueba del RFC:

Cuatro caracteres por cada tres bytes significa que Base64 ocupa un tercio más que el original: un archivo de 3.000.000 de bytes se convierte en 4.000.000 de caracteres. El correo (MIME) además parte el Base64 en líneas de 76 caracteres como máximo, lo que añade un poco más.

Base64 es una codificación, no un cifrado. Cualquiera puede decodificarlo, sin clave, así que no protege nada. Si una contraseña o un token solo parecen ilegibles porque están en Base64, no están protegidos.

El texto tiene que convertirse en bytes antes de codificarse en Base64, así que el resultado depende de la codificación del texto. La letra é da w6k= a partir de sus dos bytes en UTF-8, pero 6Q== a partir de su único byte en Latin-1. web.dev señala que la función btoa() del propio navegador solo acepta caracteres que caben en un byte y da error con los demás, como €; primero hay que convertir el texto en bytes UTF-8. La herramienta Base64 de nTools codifica el texto como UTF-8 y, al decodificar, indica si los bytes eran UTF-8 o Windows-1252.

Codificador / decodificador Base64

base64url: la versión para direcciones web

Dos de los caracteres de Base64 dan problemas fuera del texto normal. En una URL, + puede leerse como un espacio y / separa segmentos de la ruta; en un nombre de archivo, / no está permitido. Por eso el RFC 4648 define un segundo alfabeto, el seguro para URL y nombres de archivo, que suele llamarse base64url y usa - y _ en su lugar. Las especificaciones que lo usan pueden además omitir el relleno =, algo que el RFC 4648 permite cuando lo indican de forma explícita.

Los JSON Web Tokens son el ejemplo más conocido. El RFC 7515 define su codificación como base64url sin ningún = final y sin saltos de línea, y por eso las partes de un token pueden contener - y _, pero nunca +, / ni =. Un decodificador que solo conoce el Base64 estándar rechaza esas cadenas; la herramienta de nTools es uno de ellos, así que cambia - por + y _ por / antes de decodificar.

Codificación por porcentaje: texto dentro de una URL

Una URL solo puede contener un conjunto limitado de caracteres ASCII, y algunos tienen una función: / separa la ruta, ? inicia la consulta, & separa parámetros, # inicia el fragmento. El RFC 3986 (enero de 2005, estándar de Internet) fija las reglas. Las letras, las cifras y - . _ ~ pueden usarse siempre tal cual. Los caracteres con función se codifican cuando forman parte de un valor y no hacen de separador, y cualquier byte fuera del conjunto permitido se escribe como % seguido de dos cifras hexadecimales. El texto se convierte antes a UTF-8, así que un carácter fuera de ASCII se convierte en varios códigos %:

Codifica los valores que pones en una URL, no la dirección entera: codificar https://example.com/?q=1 como un solo valor convierte sus : / ? y = en códigos, lo que es correcto cuando la dirección es a su vez un parámetro de otra URL e incorrecto cuando debe funcionar como enlace. La función encodeURIComponent() de JavaScript hace justo esa codificación por valor y, como indica MDN, también deja sin codificar ! ' ( ) y *. La herramienta URL de nTools la usa.

Codificador / decodificador URL

¿Un + o %20?

Los formularios HTML envían sus datos en un formato algo distinto, application/x-www-form-urlencoded, que define el estándar URL de WHATWG. En él, un espacio se escribe como +, así que una búsqueda de a b&c=d se envía como q=a+b%26c%3Dd. En el resto de una URL, + es solo un signo más.

Esto explica una confusión habitual: decodificar a+b%20c con un decodificador de URL general da a+b c, porque ahí solo %20 es un espacio; un decodificador de formularios da a b c. Elige el decodificador que corresponda al origen del texto. MDN sugiere cambiar %20 por + después de encodeURIComponent() cuando necesitas el formato de formulario.

Doble codificación

El RFC 3986 advierte de que una cadena no debe codificarse ni decodificarse por porcentaje más de una vez. Cuando ocurre, el % de cada código se vuelve a codificar como %25:

Secuencias como %2520 o %25C3%25A9 en una dirección indican que algo codificó un texto que ya estaba codificado. Decodifica una vez, comprueba el resultado y codifica solo las partes que lo necesitan.

¿Cuál necesitas?

SituaciónUsa
Guardar o enviar texto: archivos, páginas web, JSON, CSVUTF-8
Meter bytes, como una imagen o un archivo, dentro de un texto: JSON, correo, HTMLBase64
Base64 dentro de una URL, un nombre de archivo o un tokenbase64url
Un valor dentro de una URL: un término de búsqueda, un parámetro, un segmento de rutaCodificación por porcentaje
Datos enviados por un formulario HTMLCodificación de formulario (espacios como +)
Mantener datos en secretoNinguna de estas: usa cifrado

Preguntas frecuentes

¿Base64 es una forma de cifrado?

No. Es una codificación reversible que cualquiera puede decodificar sin clave. Hace que los datos puedan viajar como texto, no que estén a salvo de ser leídos.

¿Por qué mi Base64 es distinto del de otra herramienta?

Normalmente porque el texto se convirtió en bytes con otra codificación, como Latin-1 en lugar de UTF-8, porque una herramienta usa base64url u omite el relleno =, o porque una añade saltos de línea.

¿Por qué un emoji cuenta como dos caracteres?

Muchos programas, entre ellos JavaScript, cuentan unidades UTF-16 de 16 bits, y un emoji como 😀, por encima de U+FFFF, necesita dos. En UTF-8 ocupa cuatro bytes.

¿Debo guardar los archivos en UTF-8 con BOM?

Solo cuando el programa que lee el archivo lo necesita, como Excel con los archivos CSV. Para JSON y la mayoría de los archivos web, guarda UTF-8 sin BOM.

¿Por qué mi enlace contiene %2520?

Se codificó dos veces: %20, un espacio, se volvió a codificar y su % pasó a ser %25. Decodifícalo una vez y usa el resultado.

¿Los codificadores de nTools suben mi texto?

No. La codificación y la decodificación se hacen en tu navegador y el texto no se envía a ningún sitio.

Anterior en la serie ← Los archivos CSV explicados: separadores, comillas, codificación y Excel

Referencias

  1. RFC 3629 — UTF-8, a transformation format of ISO 10646
  2. Unicode Consortium — FAQ: UTF-8, UTF-16, UTF-32 & BOM
  3. W3Techs — Usage statistics of character encodings for websites
  4. MDN — UTF-16 (glossary)
  5. RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
  6. Microsoft Support — Opening CSV UTF-8 files correctly in Excel
  7. RFC 4648 — The Base16, Base32, and Base64 Data Encodings
  8. web.dev — The nuances of base64 encoding strings in JavaScript
  9. RFC 7515 — JSON Web Signature (JWS)
  10. RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax
  11. WHATWG — URL Standard
  12. MDN — encodeURIComponent()

Guías relacionadas