Inspector de caracteres Unicode
Descompone el texto en sus puntos de código con nombres, categorías, bloques y codificaciones, y marca caracteres invisibles, bidi y sosias.
Qué hace esta herramienta
Pega cualquier texto y volverá descompuesto en los caracteres individuales de los que está hecho de verdad. Cada uno recibe su nombre Unicode, su número U+, qué clase de carácter es, a qué sistema de escritura y a qué bloque pertenece, los bytes que ocupa en UTF-8 y UTF-16, y la secuencia de escape que necesita en seis formatos distintos.
La mayoría llega aquí porque algo no cuadra. Un texto es más largo de lo que parece, dos valores que se ven idénticos se niegan a ser iguales, un nombre de usuario fue rechazado por caracteres que parecen letras normales, o una línea de código se lee distinta de como se comporta. Las cuatro tienen la misma forma: un carácter haciendo algo que la pantalla no muestra.
Caracteres, puntos de código y grafemas
La palabra «carácter» significa al menos tres cosas distintas, y confundirlas es donde empieza casi toda la confusión con Unicode. Un punto de código es un valor del estándar Unicode, escrito U+0041 o U+1F600. Un grafema es lo que quien lee cuenta como un carácter. Con frecuencia no son el mismo número.
- Una «a» normal es 1 grafema, 1 punto de código y 1 unidad UTF-16: todo coincide.
- U+00E9, la é precompuesta, es 1 grafema, 1 punto de código y 1 unidad UTF-16.
- U+0065 U+0301, esa misma letra escrita como e más un acento combinante, es 1 grafema pero 2 puntos de código y 2 unidades UTF-16.
- U+1F600, la cara sonriente, es 1 grafema y 1 punto de código pero 2 unidades UTF-16: vive por encima del BMP, así que JavaScript lo guarda como un par sustituto.
- El emoji de familia es 1 grafema, 5 puntos de código y 8 unidades UTF-16: tres personas unidas por dos unificadores invisibles.
El emoji de familia es el caso que pilla a la gente. Parece una sola cosa, JavaScript informa de una longitud de 8, y una columna de base de datos de 5 caracteres no lo aguanta. Esta herramienta agrupa los puntos de código bajo el grafema que construyen, de modo que ambas lecturas se ven a la vez en lugar de tener que reconciliarlas mentalmente.
Los caracteres que no puedes ver
Un número sorprendente de caracteres Unicode no dibuja nada en absoluto. Existen para controlar cómo se comporta el texto que los rodea, y como no dejan marca sobreviven al copiar, al pegar y a la revisión sin que nadie se dé cuenta. Estos son los que la herramienta señala en vez de limitarse a enumerar:
- Espacio, unificador y no-unificador de ancho cero (U+200B, U+200D, U+200C): sin ancho, sin marca, y rompen toda comparación de cadenas que tocan.
- Guion opcional (U+00AD): una sugerencia sobre dónde puede partirse una palabra, invisible hasta que ocurre.
- Espacio duro (U+00A0): se ve exactamente igual que un espacio y es otro carácter, por eso sobrevive tanto tiempo en los archivos de configuración.
- Marca de orden de bytes (U+FEFF): a menudo queda al principio de un archivo, donde se convierte en un primer carácter invisible del primer valor.
- Controles y anulaciones bidi (de U+202A a U+202E, de U+2066 a U+2069): reordenan el texto a su alrededor.
Los controles bidi merecen mención aparte. Se añadieron para que el hebreo y el árabe puedan mezclarse correctamente con texto latino, y hacen bien ese trabajo. Pero una anulación colocada dentro de un comentario o de una cadena puede hacer que una línea de código se muestre en un orden completamente distinto del que lee el compilador, lo que significa que un revisor puede aprobar código que hace otra cosa. Esa clase de truco se conoce como Trojan Source, y es la razón por la que esta herramienta señala cada control bidi aparte del resto de caracteres invisibles.
Caracteres sosias y mezcla de escrituras
Unicode contiene muchos caracteres visualmente idénticos a letras ASCII que no lo son. La а cirílica, la ο griega y la a latina ocupan puntos de código distintos y se dibujan igual en la mayoría de las tipografías. Un dominio o un nombre de usuario construido con ellas parece correcto y apunta a otro sitio.
Señalar cada sosia no-ASCII sería inútil: pintaría de rojo cada palabra rusa, griega o hebrea, y un aviso que salta con texto normal es un aviso que la gente aprende a saltarse. Por eso la regla aquí es la que usa el estándar de seguridad de Unicode: una palabra es sospechosa cuando las letras que hay dentro vienen de más de un sistema de escritura:
- «paypal.com» escrito enteramente con letras latinas: no hay nada que decir.
- La misma palabra con una er y una a cirílicas delante del «ypal» latino: una palabra, dos sistemas de escritura, señalada.
- Una palabra rusa entera en cirílico: un solo sistema de escritura, texto normal, no señalada.
- Una frase japonesa que usa han, hiragana y katakana a la vez: tres escrituras, un solo sistema de escritura, no señalada.
Ese último caso es la razón por la que la regla exige cuidado. El japonés se escribe con tres escrituras a la vez y el coreano mezcla dos, así que una prueba ingenua de «más de una escritura es sospechoso» declararía ataque cada frase japonesa. Las combinaciones que son genuinamente un solo sistema de escritura se tratan como una, y eso mantiene el aviso con sentido.
Normalización, o por qué dos cadenas idénticas difieren
Algunos caracteres se pueden escribir de más de una manera. La letra é es o bien el único punto de código U+00E9, o bien el par U+0065 U+0301: una e normal seguida de un acento agudo combinante. Ambas se muestran igual. Ninguna es incorrecta. No son iguales.
La normalización es el proceso de elegir una escritura, y tiene cuatro formas. NFC compone donde puede y es lo que la web asume por omisión; NFD descompone en su lugar. Las dos formas K van más lejos y además pliegan los caracteres de compatibilidad — la A de ancho completo pasa a ser una A normal, y la ligadura fi pasa a ser fi — lo cual es útil para buscar y comparar, y con pérdida para almacenar.
El panel de aquí muestra las cuatro formas de lo que pegues y marca cuáles difieren de la entrada. Si ninguna difiere, el texto ya está normalizado y el desajuste que persigues está en otra parte. Si algunas sí, lo has encontrado.
Nombres, categorías, escrituras y bloques
Cada carácter asignado lleva cuatro datos de identidad, y responden a preguntas distintas. El nombre es el carácter en sí. La categoría general dice qué clase de cosa es: una letra minúscula, una marca combinante, un símbolo de moneda, un control de formato. La escritura es el sistema de escritura al que pertenece. El bloque es el rango de puntos de código en el que fue asignado, que es un hecho organizativo y no lingüístico.
Bloque y escritura se confunden con facilidad y a menudo no coinciden. Las letras latinas viven en al menos media docena de bloques, y un bloque puede contener caracteres de varias escrituras. Cuando quieres saber «qué alfabeto es esto», la respuesta es la escritura; cuando quieres saber «dónde vive esto dentro del estándar», es el bloque.
Los nombres, las escrituras y los bloques se muestran aquí en inglés en todos los idiomas, deliberadamente. Son identificadores definidos por el estándar, no prosa: U+200D se llama ZERO WIDTH JOINER en todo el mundo, y traducirlo lo haría imposible de buscar.
Codificaciones y escapes
Un punto de código es un número; solo se convierte en bytes cuando se elige una codificación. UTF-8 usa entre uno y cuatro bytes y deja ASCII intacto, y por eso ganó. UTF-16 usa una o dos unidades de 16 bits, y es de lo que están hechas las cadenas de JavaScript, razón por la cual .length informa 2 para un solo emoji.
U+0041 41 # UTF-8: un byte, igual que ASCII U+00E9 C3 A9 # UTF-8: dos bytes U+20AC E2 82 AC # UTF-8: tres bytes U+1F600 F0 9F 98 80 # UTF-8: cuatro bytes
Cada fila aquí da también el carácter escrito como escape en JavaScript, JSON, HTML, CSS, URL y Python, listo para copiar. No son todos iguales, y la diferencia importa por encima del BMP: JavaScript y Python tienen un escape por punto de código y lo usan, mientras que JSON no tiene ninguno y debe deletrear un emoji como sus dos mitades sustitutas.
Preguntas frecuentes
- ¿Por qué mi cadena es más larga que el número de caracteres que veo?
- O contiene caracteres invisibles, o contiene grafemas construidos con varios puntos de código. Ambas cosas se muestran aquí: los caracteres invisibles se señalan, y los grafemas de varios puntos de código se agrupan para que veas el único carácter y los varios valores de los que está hecho.
- Dos cadenas se ven idénticas y no son iguales. ¿Por qué?
- Normalmente por normalización. Una letra acentuada puede ser un punto de código o una letra más una marca combinante, y ambas se dibujan igual. Pega cada cadena aquí y compara las listas de puntos de código, o mira qué formas de normalización difieren de la entrada.
- ¿Qué es un espacio de ancho cero y cómo llegó a mi texto?
- Es un carácter sin ancho y sin marca, usado para sugerir una oportunidad de salto de línea. Suele llegar al copiar texto de una página web, de un editor de documentos o de un cliente de chat, y como no se muestra nada, sobrevive a toda revisión hasta que algo compara cadenas y falla.
- ¿Cuál es la diferencia entre un punto de código y un carácter?
- Un punto de código es un valor Unicode. Un carácter en el sentido cotidiano es un grafema — lo que quien lee cuenta como uno — y un grafema puede ser varios puntos de código. Un emoji de familia son cinco puntos de código y un grafema.
- ¿Por qué la herramienta dice que algunos caracteres no tienen nombre?
- Por cuatro razones distintas, y dice cuál. Los sustitutos y los puntos de código de uso privado no tienen nombre en el estándar, los no asignados no tienen nada que nombrar, y un carácter de un bloque histórico poco consultado tiene un nombre que esta versión no incluye: la tabla de nombres conserva los bloques de los que la gente pega de verdad en lugar de enviarlos todos.
- ¿Un aviso de mezcla de escrituras es prueba de un ataque?
- No. Significa que una sola palabra toma sus letras de más de un sistema de escritura, que es la forma que tiene un nombre suplantado y también algo que el texto normal hace de vez en cuando. Es un motivo para mirar, no un veredicto.
- ¿Se envía a un servidor algo de lo que pego?
- No. La base de datos de caracteres se descarga con la página y todo se ejecuta en tu navegador; nada de lo que escribes se sube ni se registra, y funciona sin conexión de red.