O módulo unicodedata oferece acesso à base de dados oficial de caracteres Unicode usada pela versão do Python em execução. Com ele, uma aplicação pode descobrir nomes, categorias, valores numéricos, classes bidirecionais, caracteres combinantes, decomposições e formas normalizadas. Essas informações são essenciais em buscas, importação de dados, validação, geração de slugs, comparação de textos e internacionalização.
Este guia explica as funções principais e mostra como normalizar sem destruir informações importantes. A documentação do Python 3.14.6 informa que o módulo usa a Unicode Character Database 16.0.0.
Consultar a versão da base Unicode
import unicodedata
print(unicodedata.unidata_version)A versão pode afetar nomes, categorias e caracteres reconhecidos. Sistemas que persistem resultados de normalização ou validação devem registrar a versão do Python e testar upgrades.
Obter o nome de um caractere
name() devolve o nome oficial. Alguns caracteres não têm nome, então use um valor padrão quando entradas arbitrárias forem esperadas.
import unicodedata
print(unicodedata.name("½"))
print(unicodedata.name("\uFFFF", "SEM NOME"))Os nomes ajudam em depuração e relatórios. Não são traduções para o idioma do usuário, mas identificadores padronizados do Unicode.
Buscar um caractere pelo nome
lookup() realiza o caminho inverso. Se o nome não existir, gera KeyError.
chave = unicodedata.lookup("LEFT CURLY BRACKET")
print(chave)A função também reconhece aliases e sequências nomeadas suportadas pela base. Valide nomes fornecidos por usuários e trate o erro.
Categoria geral
category() retorna um código de duas letras. A primeira indica um grupo amplo, como letra, marca, número, pontuação, símbolo, separador, controle ou não atribuído. A segunda refina o tipo.
for caractere in ["A", "a", "9", "!", " "]:
print(caractere, unicodedata.category(caractere))Exemplos incluem Lu para letra maiúscula, Ll para minúscula, Nd para dígito decimal e Zs para separador de espaço. Não use apenas categorias para decidir se um identificador é seguro.
Valores decimal, digit e numeric
Unicode contém diferentes conceitos numéricos. decimal() trata dígitos decimais, digit() inclui outros dígitos e numeric() abrange valores como frações e numerais.
print(unicodedata.decimal("٩"))
print(unicodedata.digit("⁹"))
print(unicodedata.numeric("½"))Os retornos podem ser inteiros ou floats. Para validar números de entrada, defina claramente se aceita apenas ASCII, dígitos decimais internacionais ou qualquer caractere numérico.
Caracteres combinantes
combining() devolve a classe combinante canônica. Zero geralmente indica que o caractere não é uma marca combinante com classe definida.
texto = "a\u0301"
for c in texto:
print(repr(c), unicodedata.name(c), unicodedata.combining(c))A sequência contém a letra a e um acento agudo separado. Visualmente pode parecer igual a á, mas as strings podem ter comprimentos e bytes diferentes.
Por que normalizar Unicode
Unicode permite representações canonicamente equivalentes. Uma letra acentuada pode ser um caractere pré-composto ou uma letra seguida de marca combinante. Sem normalização, comparações, chaves de banco e buscas podem falhar.
a = "café"
b = "cafe\u0301"
print(a == b)
print(unicodedata.normalize("NFC", a) == unicodedata.normalize("NFC", b))Normalizar ambos os lados com a mesma forma melhora consistência, mas não resolve diferenças de caixa, idioma, pontuação ou caracteres visualmente semelhantes.
NFC e NFD
NFD aplica decomposição canônica. NFC decompõe e depois recompõe quando existe uma forma pré-composta.
nfd = unicodedata.normalize("NFD", "ação")
nfc = unicodedata.normalize("NFC", nfd)
print(repr(nfd))
print(repr(nfc))NFC é uma escolha comum para armazenamento e comparação de texto humano. NFD é útil quando é necessário analisar marcas combinantes ou remover acentos de maneira controlada.
NFKC e NFKD
As formas com K aplicam equivalência de compatibilidade. Elas podem transformar caracteres estilísticos ou históricos em formas mais simples. Por exemplo, numerais romanos e variantes de largura podem mudar.
print(unicodedata.normalize("NFKC", "Ⅳ"))
print(unicodedata.normalize("NFKC", "Full"))Essa transformação pode perder distinções relevantes. Use NFKC em identificadores e buscas somente após definir uma política. Não a aplique cegamente a assinaturas, senhas, documentos legais ou texto que precisa preservar grafia.
Verificar se já está normalizado
is_normalized() testa NFC, NFD, NFKC ou NFKD sem exigir que a aplicação compare manualmente o resultado.
texto = "café"
if not unicodedata.is_normalized("NFC", texto):
texto = unicodedata.normalize("NFC", texto)Em muitos casos, normalizar diretamente é suficientemente simples. A verificação pode ajudar em auditorias e métricas.
Remover acentos com cuidado
Um padrão comum é decompor com NFD e remover marcas. Isso não é transliteração universal e pode alterar palavras ou idiomas.
def sem_acentos(texto):
decomposto = unicodedata.normalize("NFD", texto)
filtrado = "".join(
c for c in decomposto
if unicodedata.category(c) != "Mn"
)
return unicodedata.normalize("NFC", filtrado)Use para chaves auxiliares de busca, não para substituir o texto original. Letras como ø, ł e muitos caracteres não se convertem adequadamente por esse método.
Decomposição de um caractere
decomposition() retorna códigos hexadecimais e, em alguns casos, uma tag de compatibilidade.
print(unicodedata.decomposition("Ã"))
print(unicodedata.decomposition("①"))A função é útil em ferramentas de diagnóstico, mas normalmente normalize() é a API correta para transformar texto.
Texto bidirecional
bidirectional() informa a classe usada pelo algoritmo bidirecional. mirrored() indica símbolos que podem ser espelhados em contextos da direita para a esquerda.
print(unicodedata.bidirectional("٧"))
print(unicodedata.mirrored(">"))Esses dados não substituem um motor completo de layout. Entradas bidirecionais podem ocultar ordem visual, especialmente em código, logs e nomes de arquivo. Exiba representações escapadas em ferramentas de segurança.
Largura do Leste Asiático
east_asian_width() classifica caracteres como estreitos, largos, fullwidth, halfwidth, ambíguos ou neutros.
for c in "A界F":
print(c, unicodedata.east_asian_width(c))A propriedade ajuda, mas não calcula sozinha a largura final de terminal. Combinações, emoji e políticas do terminal ainda influenciam.
Casefold e normalização
Para comparação sem diferenciar caixa, uma prática comum é normalizar e usar casefold().
def chave_busca(texto):
return unicodedata.normalize("NFKC", texto).casefold()
print(chave_busca("Straße") == chave_busca("STRASSE"))A ordem e a forma escolhidas dependem do domínio. Guarde também o original e evite usar uma chave simplificada como prova de identidade.
Segurança e caracteres semelhantes
Normalização não transforma todas as letras visualmente semelhantes na mesma coisa. O a latino, o alfa grego e o а cirílico continuam distintos. Ataques de homógrafos podem afetar nomes, domínios e identificadores.
Use políticas de scripts permitidos, bibliotecas especializadas e revisão visual para contextos de segurança. Não crie filtros baseados apenas em remover caracteres desconhecidos.
Exemplo de preparação de texto para busca
def preparar_busca(texto):
texto = unicodedata.normalize("NFKC", texto)
texto = texto.casefold()
return " ".join(texto.split())O exemplo reduz diferenças de compatibilidade, caixa e espaços. A função deve ser versionada como parte do esquema de índice, pois mudanças na base Unicode podem alterar resultados.
Erros frequentes
- Comparar texto sem uma forma normalizada definida.
- Usar NFKC quando a aparência original precisa ser preservada.
- Remover marcas e substituir o conteúdo original.
- Confundir caracteres numéricos com dígitos ASCII.
- Esperar que normalização resolva homógrafos.
- Usar largura asiática como largura visual completa.
- Ignorar a versão da base Unicode.
Boas práticas
- Preserve sempre o texto original.
- Defina a normalização por campo e finalidade.
- Normalize os dois lados da comparação.
- Versione chaves e índices derivados.
- Teste idiomas e scripts relevantes.
- Use
casefold()para comparação caseless. - Aplique controles adicionais em identificadores sensíveis.
Conteúdos relacionados
Veja textwrap, locale, fnmatch, pydoc e linecache.
Consulte a documentação oficial do unicodedata e o Unicode HOWTO.
Conclusão
unicodedata permite tratar texto internacional com regras explícitas e reproduzíveis. A normalização correta melhora buscas e comparações, mas não substitui políticas de idioma, segurança, identidade ou apresentação. Preserve o original e escolha cada transformação de acordo com o domínio.







