Por que os emojis 👩‍👩‍👧‍👦 "quebram" linhas no Swift? Análise com código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

👩‍👩‍👧‍👦: Um símbolo que enlouquece

\n\n

Imagine: você está escrevendo um aplicativo para iOS, processando texto, contando caracteres. Tudo funciona perfeitamente, até encontrar o emoji de família com três mulheres e duas meninas. Aparentemente um símbolo na tela, mas o Swift diz que são... 4 caracteres? Ou 7? Ou talvez 11? Dor familiar? Bem-vindo ao mundo do Unicode e das Strings Swift!

\n\n

Esta pergunta é uma das mais populares no Stack Overflow na seção Swift. E não é à toa. A aparente simplicidade das strings se transforma em uma verdadeira aventura quando emojis compostos entram em jogo. Neste artigo, não apenas explicaremos por que isso acontece, mas também mostraremos como trabalhar corretamente com essas strings no Swift. Se você programa em Swift e lida com processamento de entrada do usuário, emojis ou internacionalização — este material é para você.

\n\n

🔍 O problema: "Quantos caracteres há nesta string?"

\n\n

Vamos direto ao ponto. Abra o Xcode Playground e escreva:

\n\n
import Foundation\n\nlet familyEmoji = "👩‍👩‍‍👧‍👦"\nprint(familyEmoji.count) // 1? 4? 7?\n
\n\n

Se você esperava 1, está certo do ponto de vista do usuário. Se esperava 4 (quatro figuras) — também é lógico. E o Swift retornará 1. Mas tente familyEmoji.unicodeScalars.count — e obterá 7! E se analisar com utf16.count — será 11.

\n\n

Qual é o truque? O emoji 👩‍👩‍‍👧‍👦 é um cluster de grafemas composto. Ele consiste em vários escalares Unicode, unidos por caracteres invisíveis de junção (ZWJ — Zero Width Joiner). O Swift conta essas sequências como um único caractere visível (grafema), o que é correto do ponto de vista do usuário, mas confunde quando você tenta trabalhar com os "internos" da string.

\n\n

🧱 Anatomia do emoji: escalares, clusters e ZWJ

\n\n

Para entender a mágica, vamos decompor nosso emoji em suas partes. Cada caractere Unicode é um escalar (código numérico). Para 👩‍👩‍‍👧‍👦, a sequência é assim:

\n\n
let scalars = familyEmoji.unicodeScalars\nfor scalar in scalars {\n    print(scalar.value, scalar.properties.name ?? "unknown")\n}\n// Saída (simplificada):\n// 128105 (WOMAN)\n// 8205 (ZERO WIDTH JOINER)\n// 128105 (WOMAN)\n// 8205 (ZERO WIDTH JOINER)\n// 128103 (GIRL)\n// 8205 (ZERO WIDTH JOINER)\n// 128102 (BOY)\n
\n\n

Viu? Quatro figuras (duas mulheres, uma menina, um menino) unidas por três caracteres ZWJ invisíveis (código 8205). O Swift, seguindo o padrão Unicode, interpreta toda essa sequência como um único cluster de grafema estendido. É por isso que .count retorna 1 — é a quantidade de "caracteres do usuário".

\n\n

🔄 Comparação de abordagens: count vs unicodeScalars vs utf16

\n\n

Vamos sistematizar. Para a string "👩‍👩‍👧‍👦", obtemos três respostas diferentes dependendo da API que usamos:

\n\n
    \n
  • .count (clusters de grafemas) — 1. Correto para UI, exibição em UILabel.
  • \n
  • .unicodeScalars.count (escalares Unicode) — 7. Útil para processamento de texto de baixo nível.
  • \n
  • .utf16.count (unidades de código UTF-16) — 11. Usado para compatibilidade com Objective-C NSString.
  • \n
  • .utf8.count (bytes UTF-8) — 25. Para trabalho com rede e arquivos.
  • \n
\n\n

Cada uma dessas abordagens resolve um problema específico. O erro do iniciante é usar .count para limitar o comprimento da entrada em um campo de texto (por exemplo, "no máximo 140 caracteres"). Para o usuário, "👩‍👩‍👧‍👦" é um caractere, e um limite de 140 desses emojis é normal. Mas se você armazena a string em um banco de dados com comprimento fixo em bytes — você precisa de .utf8.count.

\n\n

⚙️ Casos práticos: como não se queimar

Blogs

Book Recommendations