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.
Fontes e verificação
- The Swift Programming Language: Strings and CharactersSwift.org · Documentação oficial · Consultado 23 de outubro de 2026Evidência: Fonte do contrato de implementação e da explicação. A saída foi verificada separadamente com o experimento incluído aqui.

