Elige la unidad antes de implementar un límite de texto. count en Swift mide Character, o clústeres de grafemas extendidos; los límites de transferencia suelen medir bytes. Un mismo carácter visible puede ocupar tamaños internos distintos.
Mecanismo y decisión de diseño
La sílaba hangul del experimento usa un escalar precompuesto o tres escalares jamo combinados. Swift String reconoce su equivalencia canónica, también al consultar un diccionario. Un emoji familiar reúne varios escalares en un Character. Contar otra unidad en otro lenguaje no es un error por sí mismo. Fuente primaria
Código reproducible
Los escapes Unicode fijan las entradas exactas. Compara cantidades de Character, escalares y bytes UTF-8 del hangul. Mide UTF-16 y UTF-8 del emoji, insértalo entre A y B y usa prefix y String.Index. Comprueba aparte el acceso a texto vacío.
Este ejemplo independiente se ejecutó el 2026-10-23 con Apple Swift 6.4 para arm64 macOS, en modo de lenguaje Swift 6. No necesita red ni paquetes adicionales.
Descargar el archivo Swift completo
Ejecuta el comando en la carpeta de descarga. Las precondiciones detienen la ejecución si falla una comprobación. No uses -Ounchecked: elimina estas comprobaciones.
swift -swift-version 6 swift-string-grapheme-cluster-indexing.swift
let composed = "\u{D55C}"
let decomposed = "\u{1112}\u{1161}\u{11AB}"
precondition(composed == decomposed)
precondition(composed.count == 1 && decomposed.count == 1)
precondition(composed.utf8.count == 3 && decomposed.utf8.count == 9)
precondition(decomposed.unicodeScalars.count == 3)
let lookup = [composed: 42]
precondition(lookup[decomposed] == 42)
let family = "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}"
precondition(family.count == 1 && family.unicodeScalars.count == 7)
precondition(family.utf16.count == 11 && family.utf8.count == 25)
let text = "A" + family + "B"
precondition(text.count == 3 && String(text.prefix(2)) == "A" + family)
let second = text.index(after: text.startIndex)
precondition(String(text[second]) == family)
let empty = ""
precondition(empty.first == nil && empty.prefix(2).isEmpty)
print("hangul=characters:1,scalars:1/3,utf8:3/9 equal:true dictionary:42")
print("family=characters:1,scalars:7,utf16:11,utf8:25 prefix=2 empty=safe")
Salida registrada e interpretación
hangul=characters:1,scalars:1/3,utf8:3/9 equal:true dictionary:42
family=characters:1,scalars:7,utf16:11,utf8:25 prefix=2 empty=safe
Ambas formas hangul tienen un Character, pero usan 3 y 9 bytes UTF-8; la descompuesta tiene tres escalares. La clave equivalente devuelve 42. El emoji familiar tiene un Character, siete escalares, once unidades UTF-16 y veinticinco bytes UTF-8. prefix(2) conserva el emoji completo.
Alcance y limitaciones
Character no modela perfectamente toda noción humana de letra; importan reglas de segmentación y versiones Unicode. No supongas tres bytes por carácter hangul visible o emoji. Swift Dictionary no exige siempre normalización NFC explícita, pero hay que verificar contratos externos de comparación y codificación.
Qué comprobar después
Acuerda si los límites del servidor y cliente cuentan caracteres o bytes UTF-8. Usa API como prefix para vistas previas. Si repites accesos aleatorios, evalúa coste y memoria de convertir a array. El ejemplo Optional distingue texto ausente de texto vacío.
Fuentes y verificación
- The Swift Programming Language: Strings and CharactersSwift.org · Documentación oficial · Consultado 23 de octubre de 2026Respalda: Fuente del contrato de implementación y de la explicación. La salida se comprobó por separado con el experimento incluido aquí.

