ios swift unicode emoji countelements

ios - Swift countElements() devuelve un valor incorrecto cuando cuenta el emoji de la bandera



unicode (2)

let str1 = "πŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺ" let str2 = "πŸ‡©πŸ‡ͺ.πŸ‡©πŸ‡ͺ.πŸ‡©πŸ‡ͺ.πŸ‡©πŸ‡ͺ.πŸ‡©πŸ‡ͺ." println("/(countElements(str1)), /(countElements(str2))")

Resultado: 1, 10

¿Pero no debería str1 tener 5 elementos?

El error parece ocurrir solo cuando uso el emoji de la bandera.


Así es como resolví ese problema, para Swift 3 :

let str = "πŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺ" //or whatever the string of emojis is let range = str.startIndex..<str.endIndex var length = 0 str.enumerateSubstrings(in: range, options: NSString.EnumerationOptions.byComposedCharacterSequences) { (substring, substringRange, enclosingRange, stop) -> () in length = length + 1 } print("Character Count: /(length)")

Esto soluciona todos los problemas con el recuento de caracteres y los emojis, y es el método más simple que he encontrado.


Actualización para Swift 4 (Xcode 9)

A partir de Swift 4 (probado con Xcode 9 beta), los grupos de grafemas se rompen después de cada segundo símbolo indicador regional, como lo exige el estándar Unicode 9:

let str1 = "πŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺ" print(str1.count) // 5 print(Array(str1)) // ["πŸ‡©πŸ‡ͺ", "πŸ‡©πŸ‡ͺ", "πŸ‡©πŸ‡ͺ", "πŸ‡©πŸ‡ͺ", "πŸ‡©πŸ‡ͺ"]

También String es una colección de sus caracteres (de nuevo), por lo que se puede obtener el recuento de caracteres con str1.count .

(Respuesta anterior para Swift 3 y mayores :)

De "3 Grapheme Cluster Boundaries" en el "Anexo Estándar # 29 SEGMENTACIÓN DE TEXTO DE UNICODE": (énfasis agregado):

Un grupo de grafemas heredados se define como una base (como A o γ‚«) seguido de cero o más caracteres continuos. Una forma de pensar en esto es como una secuencia de caracteres que forman una "pila".

La base puede ser caracteres individuales, o puede ser cualquier secuencia de caracteres Hangul Jamo que formen una sílaba Hangul, según lo definido por D133 en El estándar Unicode, o puede ser cualquier secuencia de caracteres Regional_Indicator (RI) . Los caracteres RI se utilizan en pares para indicar los símbolos de la bandera nacional Emoji correspondientes a los códigos de país ISO. Las secuencias de más de dos caracteres RI deben estar separadas por otros caracteres , como U + 200B ZWSP.

(Gracias a @rintaro por el enlace).

Un carácter rápido representa un grupo de grafemas extendido, por lo que es correcto (según esta referencia) que cualquier secuencia de símbolos indicadores regionales se cuente como un solo carácter.

Puede separar las "banderas" por un CERO ANCHO SIN UNIÓN:

let str1 = "πŸ‡©πŸ‡ͺ/u{200C}πŸ‡©πŸ‡ͺ" print(str1.characters.count) // 2

o inserte un ESPACIO DE ANCHO CERO:

let str2 = "πŸ‡©πŸ‡ͺ/u{200B}πŸ‡©πŸ‡ͺ" print(str2.characters.count) // 3

Esto también resuelve posibles ambigüedades, por ejemplo, ¿debería "πŸ‡« πŸ‡· πŸ‡Ί πŸ‡Έ" ser "πŸ‡« πŸ‡·πŸ‡Ί πŸ‡Έ" o "πŸ‡«πŸ‡· πŸ‡ΊπŸ‡Έ"?

Consulte también ¿Cómo saber si dos emojis se mostrarán como un emoji? acerca de un posible método para contar el número de "caracteres compuestos" en una cadena Swift, que devolvería 5 para su let str1 = "πŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺπŸ‡©πŸ‡ͺ" .