unicodedata no Python: normalize Unicode

Publicado em: 11/08/2026
Tempo de leitura: 6 minutos
Alfabeto tridimensional representando normalização Unicode com unicodedata no Python

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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Rede de servidores representando gerenciamento de recursos com ExitStack no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ExitStack no Python: gerencie recursos

    Aprenda ExitStack no Python para gerenciar arquivos, conexões e limpezas dinâmicas com segurança e ordem previsível.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026
    Pasta com cadeado representando tipos e permissões com stat no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    stat no Python: tipos e permissões

    Aprenda stat no Python para interpretar tipos de arquivo, permissões, links, timestamps, atributos do Windows e flags de Unix com

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Notebook com código representando documentação automática com pydoc no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pydoc no Python: documentação automática

    Aprenda pydoc no Python para gerar ajuda no terminal, HTML e servidor local a partir de docstrings, com segurança ao

    Ler mais

    Tempo de leitura: 7 minutos
    10/08/2026
    Teclado internacional representando números, moedas e datas com locale no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    locale no Python: números, moedas e datas

    Aprenda locale no Python para formatar e interpretar números, moedas, datas e ordenação cultural sem erros de concorrência.

    Ler mais

    Tempo de leitura: 8 minutos
    09/08/2026
    Monitor e rede representando informações de sistema com platform no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    platform no Python: informações do sistema

    Aprenda platform no Python para identificar sistema operacional, arquitetura, distribuição, versão do Python e ambiente com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    09/08/2026
    Código e compilador representando caminhos e variáveis de build com sysconfig no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sysconfig no Python: caminhos e build

    Aprenda sysconfig no Python para descobrir caminhos de instalação, variáveis de build, headers, virtualenvs e plataformas com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    09/08/2026