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

    Código Python representando functools.Placeholder e argumentos posicionais
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    functools.Placeholder: argumentos flexíveis no partial

    Aprenda functools.Placeholder no Python 3.14 para preencher argumentos posicionais flexíveis com partial e partialmethod.

    Ler mais

    Tempo de leitura: 5 minutos
    17/10/2026
    Código em tela representando t-strings no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    T-strings no Python 3.14: templates estruturados

    Aprenda t-strings no Python 3.14, entenda Template e Interpolation e crie renderizadores estruturados, extensíveis e mais seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    16/10/2026
    CPU e módulos de memória representando shared_memory track no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    shared_memory track: controle o resource tracker

    Aprenda o parâmetro track de multiprocessing.shared_memory no Python para controlar o resource tracker e evitar remoções prematuras.

    Ler mais

    Tempo de leitura: 6 minutos
    16/10/2026
    Unidade de armazenamento de dados representando compactação com compression.zstd no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: streams e compressão segura

    Aprenda compression.zstd no Python para compactar arquivos e dados com velocidade, streaming, dicionários e segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    15/10/2026
    Código em tela para diagnóstico de processos com sys.remote_exec no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sys.remote_exec: diagnostique processos Python

    Aprenda sys.remote_exec no Python para diagnosticar processos em execução com scripts controlados, segurança e boas práticas.

    Ler mais

    Tempo de leitura: 6 minutos
    15/10/2026
    Código Python e configuração de variáveis de ambiente com os.reload_environ
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    os.reload_environ: riscos com threads e ambiente

    Aprenda os.reload_environ no Python para atualizar variáveis de ambiente alteradas externamente, validar configurações e evitar problemas com threads.

    Ler mais

    Tempo de leitura: 5 minutos
    14/10/2026