Swift e Objective-C

Tamanho de String em Swift: meça hangul, emoji e bytes

Compare Character, escalares, UTF-16 e UTF-8; verifique chaves hangul equivalentes e recorte um emoji de família sem parti-lo.

2 min de leitura
Imagem de capa de Tamanho de String em Swift: meça hangul, emoji e bytes

Escolha a unidade antes de implementar um limite de texto. count em Swift mede Character, ou clusters de grafemas estendidos; limites de transferência normalmente medem bytes. Um mesmo caractere exibido pode ter tamanhos internos diferentes.

Mecanismo e decisão de projeto

A sílaba hangul do experimento usa um escalar pré-composto ou três escalares jamo combinados. Swift String considera a equivalência canônica, inclusive na busca em dicionário. Um emoji de família reúne vários escalares em um Character. Contar outra unidade em outra linguagem não é um erro por si só. Fonte primária

Código reproduzível

Escapes Unicode fixam as entradas exatas. Compare as contagens de Character, escalares e bytes UTF-8 do hangul. Meça UTF-16 e UTF-8 do emoji, coloque-o entre A e B e use prefix e String.Index. Verifique separadamente o acesso a texto vazio.

Este exemplo independente foi executado em 2026-10-23 com Apple Swift 6.4 para arm64 macOS, no modo de linguagem Swift 6. Não requer rede nem pacotes adicionais.

Baixar o arquivo Swift completo

Execute o comando na pasta do download. As precondições interrompem a execução se uma verificação falhar. Não use -Ounchecked: essa opção remove as verificações.

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")

Saída registrada e interpretação

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

As duas formas hangul têm um Character, mas usam 3 e 9 bytes UTF-8; a decomposta tem três escalares. A chave equivalente retorna 42. O emoji tem um Character, sete escalares, onze unidades UTF-16 e vinte e cinco bytes UTF-8. prefix(2) preserva o emoji inteiro.

Escopo e limitações

Character não representa perfeitamente toda noção humana de letra; regras de segmentação e versões Unicode importam. Não suponha três bytes por caractere hangul exibido ou emoji. Swift Dictionary nem sempre exige normalização NFC explícita, mas contratos externos de comparação e codificação devem ser conferidos.

O que verificar em seguida

Combine se servidor e cliente limitam caracteres ou bytes UTF-8. Use APIs como prefix para prévias. Para acessos aleatórios repetidos, avalie custo e memória da conversão em array. O exemplo Optional diferencia texto ausente de texto vazio.

Experimento relacionado

Fontes e verificação