Saltar al contenido principal
🔤 Estándares entre lenguajes Estándar: Unicode Standard Annex #29 / UTS #51 Time: 6 min de lectura Revisado: septiembre de 2024

Clústeres de grafemas: recuento

Cómo procesar con seguridad los caracteres percibidos por el usuario según el UAX #29 de Unicode, sin truncar los emojis ni separar los caracteres combinantes.

TL;DR — Respuesta directa

Respuesta técnica directa

Un clúster de grafemas es una secuencia de uno o más puntos de código de Unicode que representa un único carácter percibido por el usuario en pantalla. El conteo de puntos de código falla con los caracteres compuestos (p. ej., e + acento agudo) y con los emojis (p. ej., secuencias ZWJ, tonos de piel, banderas).

💡
Regla de producción: Para medir, invertir o truncar texto visible con seguridad, el software debe segmentarlo según los límites de los clústeres de grafemas extendidos, utilizando bibliotecas estándar conforme al UAX #29 de Unicode (como Intl.Segmenter en JavaScript, regex \X en PCRE/Python o grapheme_* en PHP).

Los cuatro niveles de representación del texto

Comprender el procesamiento de texto exige diferenciar las cuatro capas, desde el almacenamiento físico hasta la representación visual.

1. Bytes (octetos)

Bytes físicos en memoria o a través de la red (p. ej., 4 bytes 0xF0 0x9F 0x98 0x80 para 😀 en UTF-8).

2. Unidades de código

La unidad mínima de almacenamiento de una codificación (p. ej., dos unidades de código de 16 bits 0xD83D 0xDE00 en UTF-16).

3. Puntos de código

Los números de carácter individuales de Unicode (p. ej., U+1F600 para 😀, o U+0065 y U+0301 para la é descompuesta).

4. Clústeres de grafemas

El glifo real que el usuario percibe en pantalla. Definido formalmente en el Unicode Standard Annex #29, un clúster de grafemas extendido trata los caracteres base, las marcas sin espaciado, los modificadores de tono de piel y los zero-width joiners como una unidad indivisible.

Contar los caracteres percibidos por el usuario en texto compuesto y emojis

JAVASCRIPT grapheme-segmentation.js
// 1. Combining mark: 'e' (U+0065) + combining acute (U+0301)
const accented = 'e\u0301';
console.log(accented.length); // 2 code units
console.log([...accented].length); // 2 code points

// 2. Woman Technologist: Woman + ZWJ + Laptop
const tech = '👩‍💻';
console.log(tech.length); // 5 code units
console.log([...tech].length); // 3 code points

// 3. User-perceived character counting via Intl.Segmenter
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
console.log([...segmenter.segment(accented)].length); // 1 visual character!
console.log([...segmenter.segment(tech)].length); // 1 visual character!
Salida del programa
2
2
5
3
1
1

Cómo funcionan las reglas de límites de los clústeres de grafemas

El UAX #29 de Unicode especifica reglas de ruptura basadas en máquinas de estados que determinan si dos puntos de código adyacentes permanecen unidos o se separan.

Regla GB9: no romper antes de los caracteres combinantes

Cualquier marca sin espaciado (Grapheme_Extend) o carácter combinante espaciado se liga al carácter base que lo precede. Una «e» seguida de U+0301 nunca se rompe entre la «e» y el acento.

Regla GB11: no romper dentro de las secuencias de emojis con ZWJ

Cuando un zero-width joiner (U+200D) aparece entre caracteres pictográficos, la secuencia permanece intacta. Hombre + ZWJ + portátil forma un único clúster de grafemas indivisible.

Regla GB12/13: pares de indicadores regionales para las banderas

Dos símbolos de indicadores regionales (p. ej., U+1F1FA y U+1F1F3 para la ONU) se ligan para formar un único clúster de grafemas de bandera.

Errores comunes frente a patrones de producción

Aprenda qué patrones fallan en producción y cuáles son las alternativas modernas conformes con los estándares.

Invertir una cadena de forma segura

Utilidades de manipulación de texto, palíndromos, animaciones.
EVITAR: ❌ split/reverse/join ingenuo
'e\u0301'.split('').reverse().join('')
// Produces '\u0301e' — floating accent detached from base letter!
Por qué falla: Invierte el orden de los caracteres, colocando el carácter combinante antes de la letra base o separando los pares sustitutos.
RECOMENDADO: ✅ Inversión con conocimiento de grafemas
const seg = new Intl.Segmenter('en', { granularity: 'grapheme' });
const chars = Array.from(seg.segment('e\u0301'), s => s.segment);
chars.reverse().join('');
// Correctly keeps 'é' intact!
Por qué es mejor: Trata el clúster compuesto completo como un único token durante la inversión.

Matriz de casos límite e invariantes

Una matriz de pruebas diversa entre caracteres que compara el comportamiento de los caracteres en ASCII, marcas combinantes, emojis, banderas y fragmentos sustitutos.

Caso de prueba Glifo de entrada Unidades de código Puntos de código Grafemas Categoría Explicación técnica
Carácter latino Z 1 1 ASCII El punto de código único U+005A es 1 clúster de grafemas.
Carácter base + 2 caracteres combinantes ö́ 3 1 Multiple Combining Marks Letra o + diéresis + acento agudo. 3 puntos de código forman 1 clúster visual.
Emoji con tono de piel 👍🏽 2 1 Emoji Modifier Pulgar hacia arriba (U+1F44D) + tono de piel medio (U+1F3FD). 1 clúster de grafemas.
Emoji de familia con ZWJ 👩‍👩‍👦‍👦 7 1 ZWJ Sequence Mujer + ZWJ + Mujer + ZWJ + Niño + ZWJ + Niño. 7 puntos de código forman 1 familia visual.

Procedencia de estándares y fuentes

Todos los invariantes técnicos, las API y los comportamientos de esta guía se verifican contra las especificaciones primarias oficiales.

Unicode Consortium

Unicode Standard Annex #29: Unicode Text Segmentation

Cláusula: §3 Grapheme Cluster Boundaries

Unicode Consortium

Unicode Technical Standard #51: Unicode Emoji

Cláusula: §2.2 Emoji Sequences