Introducción: ¿Por qué la "longitud de una cadena" no es solo un número?
\n\nImagine que está escribiendo una aplicación para iOS. El usuario ingresa su nombre en un campo de texto. ¿Sencillo? ¿Y si el nombre contiene emojis, signos diacríticos (por ejemplo, "café") o jeroglíficos? De repente, la simple tarea de "obtener la longitud de una cadena" se convierte en un detective con elementos de Unicode.
\n\nEn Swift, trabajar con cadenas no es solo contar caracteres. Es un viaje al mundo de los clústeres de grafemas, escalares Unicode y el legado de Objective-C (sí, NSString todavía está con nosotros). Si recién está comenzando a aprender Swift o viene de otros lenguajes, este artículo es para usted. Analizaremos cómo determinar correctamente la longitud de una cadena, qué trampas le esperan y cuándo usar count y cuándo NSString.
Este material se basa en una pregunta popular real de Stack Overflow. Miles de desarrolladores han tropezado con este tema. No repitamos sus errores. ¡Allá vamos!
\n\n\n\n
1. Conceptos básicos: la propiedad count de String
\n\nLa forma más obvia de obtener la longitud de una cadena en Swift es usar la propiedad count. Devuelve la cantidad de "caracteres" (Character) en la cadena. Pero, ¿qué es un carácter para Swift?
let greeting = "¡Hola, mundo!"\nprint(greeting.count) // 13 (incluyendo espacio y signo de exclamación)\n\nFunciona como se esperaba. Pero compliquemos la tarea:
\n\nlet emojiString = "👨👩👧👦"\nprint(emojiString.count) // 1 (!!!)\n\n¿Uno? ¿En serio? Visualmente es una familia de cuatro personas. ¿Cuál es el truco?
\n\nLa respuesta está en cómo Swift maneja las cadenas. count no cuenta bytes ni caracteres Unicode individuales, sino clústeres de grafemas (extended grapheme clusters). Esta es una secuencia de uno o más escalares Unicode que el usuario percibe como un solo carácter. El emoji "familia" consta de varias partes, pero Swift lo cuenta como un solo carácter porque así lo ve una persona.
Este comportamiento no es un error, sino una característica. Swift está diseñado teniendo en cuenta la internacionalización. Si count contara cada escalar Unicode, la cadena "café" (con un solo carácter é) podría dar un resultado diferente dependiendo de cómo esté codificada é: como un solo carácter U+00E9 o como una combinación de e + acento (U+0065 + U+0301).
let cafe1 = "café" // é como un solo carácter\nlet cafe2 = "cafe\\u{0301}" // e + acento\nprint(cafe1.count) // 4\nprint(cafe2.count) // 4 (aunque la cadena tiene 5 escalares)\n\nSwift cuenta ambas variantes como 4 caracteres porque el usuario ve "café" de 4 letras. Esta es la magia de los clústeres de grafemas.
\n\n\n\n
2. Enfoque alternativo: NSString y la propiedad length
\n\nA veces necesita obtener no la cantidad "humana" de caracteres, sino la cantidad de unidades de codificación UTF-16. Por ejemplo, al trabajar con API heredadas, Core Text o al transferir datos en formatos que esperan una longitud en UTF-16 (como algunos protocolos de red).
\n\nAquí viene al rescate NSString, la vieja clase de Objective-C. Las cadenas de Swift se puentean (bridge) automáticamente a NSString, por lo que puede usar su propiedad length:
let swiftString = "👨👩👧👦"\nlet nsString = swiftString as NSString\nprint(nsString.length) // 11 (cantidad de unidades UTF-16)\n\n¿Por qué 11? Porque el emoji compuesto "familia" en UTF-16 ocupa 11 unidades (cada componente se codifica con un par sustituto o un carácter individual). Si trabaja con texto que será procesado por bibliotecas C antiguas o API que esperan NSString, use length. Pero recuerde: esto no es la cantidad de caracteres que ve el usuario.
Otro matiz: NSString no tiene en cuenta los clústeres de grafemas. Para la cadena "café" (segunda variante), length devolverá 5, aunque count devuelve 4. Conclusión: elija el mét