Radar IA 19 de outubro de 2026
✨ IA MÁGICA Agentes · Modelos · Automação
ÚLTIMAS
Tutoriais e Guias

Separadores invisiveis em arquivos de texto: como preparar para a IA

Espaco nao separavel, BOM e caracteres de largura zero quebram a busca exata. Veja como detectar e normalizar antes de enviar o texto para uma IA.

Separadores invisiveis em arquivos de texto: como preparar para a IA
Imagem: capa editorial — Tutoriais e Guias

Separadores invisíveis são caracteres que existem no arquivo mas não aparecem na tela: espaço não separável, espaço fino, hífen suave, marca de ordem de bytes (BOM), caracteres de largura zero e tabulações escondidas. Eles quebram a divisão de colunas, a contagem de palavras e a busca exata no momento em que o arquivo entra num pipeline de IA, porque um campo que parece igual a outro nunca é igual byte a byte.

Antes de enviar texto para uma IA, normalize o arquivo: remova o BOM, troque espaços não separáveis por espaço comum, elimine caracteres de largura zero e aplique uma normalização Unicode adequada (NFC para texto geral, NFKC para identificadores). Este guia mostra quais são esses caracteres, por que aparecem, o que estragam e como detectar e limpar.

Resumo rápido

  • Espaço não separável (U+00A0) parece um espaço comum, mas é um caractere diferente, e nenhuma comparação exata o considera igual.
  • O BOM (U+FEFF) costuma aparecer no início de arquivos exportados e pode virar um “primeiro caractere” que estraga a primeira linha ou o primeiro cabeçalho.
  • Caracteres de largura zero (U+200B, U+200C, U+200D) e o hífen suave (U+00AD) não têm largura visível e sobrevivem a cópias de páginas e de PDFs.
  • Normalização Unicode resolve diferenças de representação: NFC para texto geral, NFKC para identificadores e comparações flexíveis.
  • Detecte com um editor que mostra invisíveis ou com hexdump, e limpe na entrada do pipeline, não no meio dele.
  • Limpe uma vez, na ingestão, e teste com buscas exatas por códigos de produto e por nomes com acento.

Quais são esses caracteres e por que eles existem

A maioria desses caracteres não é erro: eles resolvem problemas reais de tipografia e de internacionalização. O problema aparece quando o arquivo passa por um pipeline que trata texto como dados estruturados.

Caractere Código Unicode Para que serve O que estraga
Espaço não separável U+00A0 Impedir que duas palavras se separem em duas linhas Divisão por espaço, contagem de palavras, busca exata
Espaço fino U+2009 Espaçamento tipográfico mais estreito Divisão por espaço, alinhamento de colunas
Espaço estreito sem quebra U+202F Espaço estreito e não separável Comparação de strings, campos delimitados
Hífen suave U+00AD Marcar onde uma palavra pode ser quebrada Busca exata, extração de nomes e códigos
Marca de ordem de bytes (BOM) U+FEFF Sinalizar codificação UTF-8/UTF-16 no início do arquivo Primeiro cabeçalho, chave da primeira linha JSON
Espaço de largura zero U+200B Permitir quebra de linha sem adicionar espaço visível Busca exata, comparação de identificadores
Não união de largura zero U+200C Controle de ligadura e escrita em certos idiomas Contagem de caracteres, busca exata
União de largura zero U+200D Combinar emoji e ligaduras Contagem de caracteres, igualdade de sequências
Tabulação U+0009 Alinhar colunas em texto puro Campos separados, se o divisor esperado for outro

Esses códigos pertencem a blocos diferentes. O espaço fino, o espaço estreito sem quebra e os caracteres de largura zero estão na faixa U+2000 em diante, cujo mapa oficial está no quadro de caracteres de pontuação geral Unicode (PDF oficial). O papel do BOM e das codificações está descrito nas diretrizes do W3C sobre uso do BOM em UTF-8.

Quando esses caracteres aparecem nos seus arquivos

Eles entram no arquivo por caminhos previsíveis:

  • Exportação de editores de texto e de planilhas. Muitos exportadores gravam CSV com BOM para que o Excel reconheça o UTF-8. O resultado é um \ufeff invisível colado no primeiro cabeçalho da planilha.
  • Cópia de páginas web. Páginas usam espaço não separável e caracteres de largura zero para controlar quebra de linha. Copiar de um site traz esses caracteres junto.
  • Cópia de PDF. A extração de PDF produz marcadores de posição, hífen suave de hifenização e espaços não separáveis que estavam na diagramação.
  • Campos de formulário e sites de terceiros. Um catálogo copiado de outro site carrega o espaço não separável que separava número de unidade naquela página.
  • Geração automática de relatórios. Ferramentas que formatam números com espaço fino entre grupos mantêm esse caractere no texto exportado.

O que eles estragam num pipeline de IA

Chunking

Quando um sistema dorado de IA divide um documento em pedaços, a divisão costuma se apoiar em pontuação e quebras de linha. Um espaço não separável no lugar de uma quebra pode manter junta uma unidade que deveria ser separada, ou separar o que deveria ficar junto. O efeito é sutil e aparece como trechos que começam ou terminam no meio de um valor, como destacado no guia de embeddings e o que eles representam.

Campos separados

Se o divisor esperado é a tabulação e o arquivo tem espaços não separáveis, as colunas grudadam. Se o divisor é a vírgula e o campo tem vírgula dentro, o mesmo acontece. É por isso que um CSV exportado de planilha costuma abrir com a primeira coluna “suja”: ela contém o BOM antes do primeiro cabeçalho.

Comparação de strings

Comparações exatas (==) usam a representação binária. Um “10 000” com espaço não separável nunca é igual a “10 000” com espaço comum, mesmo que pareçam idênticos na tela. O mesmo vale para nomes com acento representados de formas diferentes: a letra “é” pode ser um único caractere ou uma sequência de “e” mais acento combinante, e as duas codificações não são iguais byte a byte sem normalização.

Extração de valores

Um agente que extrai preços ou códigos de um campo espera um padrão numérico ou alfanumérico. Um espaço não separável no meio do número, ou um BOM na frente do primeiro valor, faz o padrão falhar e o valor sair vazio ou errado, sem erro visível.

Busca exata

Buscas por código de produto, número de nota ou identificador exigem igualdade exata. Qualquer invisível escondido no meio reprova a busca, e a causa não aparece na tela. É o caso mais comum de falha em pipeline de catálogo, como mostra o exemplo mais adiante.

Como detectar os invisíveis

Você tem quatro ferramentas práticas. Escolha a que combina com o volume do problema.

  • Editor com visualização de caracteres. Editores de código oferecem renderizar espaços, tabulações e controles. É suficiente para inspecionar uma linha suspeita.
  • hexdump. Mostrar os bytes revela a codificação real: xxd arquivo.txt | head mostra, por exemplo, um efbbbf no início, que é o BOM em UTF-8.
  • Script de varredura. Um trecho curto de código percorre o arquivo e lista posições de caracteres especiais. É o caminho para milhares de arquivos.
  • Filtro por código Unicode. Comparar cada caractere com uma lista de códigos permitidos, por exemplo, tudo que for letra, número, espaço comum, tabulação e pontuação básica, e apontar o que estiver fora.

Em Python, o módulo unicodedata da biblioteca padrão expõe o nome de cada caractere, o que ajuda a identificar o que apareceu; os detalhes estão na documentação oficial do módulo unicodedata. Uma varredura simples fica assim:

import unicodedata

SUSPEITOS = {"\u00a0", "\u2009", "\u202f", "\u00ad", "\u200b", "\u200c", "\u200d", "\ufeff"}

def varrer(caminho):
    with open(caminho, "r", encoding="utf-8", errors="replace") as f:
        for numero, linha in enumerate(f, start=1):
            for coluna, ch in enumerate(linha, start=1):
                if ch in SUSPEITOS or (not ch.isprintable() and ch != "\t"):
                    nome = unicodedata.name(ch, "SEM NOME")
                    print(f"linha {numero}, coluna {coluna}: U+{ord(ch):04X} {nome}")

varrer("catalogo.csv")

O script lê o arquivo como UTF-8, percorre caractere a caractere e imprime a posição, o código e o nome de cada invisível encontrado. unicodedata.name devolve o nome oficial do caractere e aceita um valor padrão quando o caractere não tem nome. O teste isprintable pega os controles que não passam pela lista, mantendo a tabulação de fora.

Como normalizar e limpar

A limpeza tem quatro etapas, na ordem: remover o BOM, trocar espaços não separáveis por espaço comum, remover caracteres de largura zero e aplicar a forma de normalização Unicode que faz sentido. As duas últimas dependem de julgamento, e é aqui que a normalização Unicode entra.

A normalização é um processo formal que escolhe uma representação única entre sequências de caracteres equivalentes. A norma UAX #15, Unicode Normalization Forms define quatro formas. As duas usadas no dia a dia são NFC e NFKC. Na NFC, o texto é representado na forma pré-composta, em que a maioria dos acentos vira um único caractere. Na NFKC, além disso, aplicam-se decomposições de compatibilidade, que depois são compostas. A recomendação prática, que aparece no FAQ oficial de normalização da Unicode, é usar NFC para texto geral e NFKC para identificadores e comparações flexíveis. A diferença entre equivalência canônica e de compatibilidade está no próprio UAX #15: a canônica diz que duas representações são o mesmo caractere; a de compatibilidade é mais fraca, diz que representam o mesmo conceito, mas podem ter aparência ou comportamento diferentes.

Atenção a um ponto: a NFKC “abre” distinções que em alguns contextos são propositais. Por isso ela serve para identificadores e busca, mas não deve ser aplicada a texto que precisa preservar detalhes tipográficos. A limpeza completa em Python fica assim:

import unicodedata

def normalizar(texto, forma="NFC"):
    if texto.startswith("\ufeff"):
        texto = texto[1:]
    texto = texto.replace("\u00a0", " ").replace("\u2009", " ").replace("\u202f", " ")
    for invisivel in ("\u200b", "\u200c", "\u200d", "\u00ad"):
        texto = texto.replace(invisivel, "")
    texto = texto.replace("\r\n", "\n").replace("\r", "\n")
    return unicodedata.normalize(forma, texto)

with open("catalogo.csv", "r", encoding="utf-8") as entrada:
    conteudo = normalizar(entrada.read(), forma="NFKC")

with open("catalogo_limpo.csv", "w", encoding="utf-8") as saida:
    saida.write(conteudo)

unicodedata.normalize(forma, texto) aplica a forma pedida e é idempotente, aplicar de novo não muda o resultado. A escolha entre NFC e NFKC é sua: use NFC quando o texto será exibido, NFKC quando será comparado como identificador. Se a limpeza envolve milhares de arquivos, rode a varredura primeiro para saber o que existe e limpe só depois. Em bash, uma verificação rápida de BOM usa file ou xxd para olhar os primeiros bytes:

# mostra se o arquivo começa com BOM (efbbbf em UTF-8)
head -c 3 catalogo.csv | xxd

# remove BOM do começo de um arquivo, preservando o resto
sed -i '1s/^\xEF\xBB\xBF//' catalogo.csv

O primeiro comando mostra os três primeiros bytes, e efbbbf confirma a presença do BOM. O segundo remove apenas se ele estiver na primeira linha, que é a forma comum. Para espaços não separáveis e caracteres de largura zero em lote, o Python costuma ser mais claro e mais seguro do que sed, porque trabalha com a string desmontada em caracteres, não com bytes, como lembra a introdução da documentação do Python ao Unicode.

Exemplo: o código de produto que não era encontrado

Uma equipe de gestão de catálogo em Belo Horizonte exportou a lista de produtos de um portal de fornecedor e montou uma busca por código de produto para um assistente interno. O código tinha o formato de uma sigla seguida de número, e na tela do portal os códigos apareciam corretos, separados por espaço. A busca no sistema da equipe falhava para uma parte considerável dos itens e não havia erro: o assistente simplesmente respondia que não encontrou aquele código.

A causa estava no separador. O portal do fornecedor usava um espaço não separável entre a sigla e o número, para não deixar o código quebrar de linha em telas estreitas. Ao copiar e exportar, esse caractere veio junto. Na tela do editor da equipe ele parecia um espaço comum, então ninguém suspeitou. Mas a busca por igualdade exata comparava o código digitado, com espaço comum, com o código do catálogo, com espaço não separável, e os dois nunca batiam. O mesmo problema aparecia na contagem de caracteres do código e em qualquer divisão por espaço que tentasse separar sigla e número.

A correção foi inserir uma etapa de limpeza entre a exportação do fornecedor e a carga no sistema: remover o BOM do cabeçalho do CSV, trocar os espaços não separáveis por espaço comum e aplicar NFKC ao campo de código, que funciona como identificador. A busca passou a encontrar os códigos. O ganho não veio de trocar o modelo nem de reescrever prompts: veio de garantir que o texto que entra no pipeline é o texto que a comparação espera. A equipe passou a rodar a varredura de caracteres suspeitos como conferência antes de cada carga e a manter o resultado registrado, ligando a lição à rotina de conferência de respostas da IA.

Erros comuns

  • Limpar dentro do pipeline. Fazer a troca no meio do processo, e não na entrada, deixa passar os invisíveis que entram pelas etapas intermediárias.
  • Aplicar NFKC em tudo. A forma é apropriada para identificadores e busca, mas mexe em distinções de compatibilidade que podem ter significado em outros textos.
  • Confundir “parece igual” com “é igual”. Dois textos visualmente idênticos podem ter bytes diferentes e falhar em qualquer comparação exata.
  • Remover todo espaço. Trocar espaços não separáveis por vazio junta palavras que deveriam estar separadas. Em campos separados, use o separador correto, não a remoção.
  • Esquecer o BOM. É o invisível mais frequente em CSV exportado e o que mais estraga o primeiro cabeçalho ou a primeira chave de um JSON.
  • Limpar depois de indexar. Se os vetores foram gerados com o texto sujo, limpar o original não corrige o índice. Limpe antes de gerar embeddings e reindexe quando o texto muda.
  • Não registrar a limpeza. Sem saber o que foi alterado, uma divergência futura entre original e processado fica sem explicação.

Perguntas frequentes

Qual a diferença entre NFC e NFKC?

NFC usa equivalência canônica: representa o mesmo caractere de uma forma única, geralmente pré-composta, sem mexer em caracteres que só são equivalentes por compatibilidade. NFKC aplica também as decomposições de compatibilidade, o que aproxima formas que se parecem, por exemplo, letras de largura completa e largura normal. A recomendação oficial é NFC para texto geral e NFKC para identificadores.

Preciso normalizar antes de gerar embeddings?

Sim, se o mesmo texto pode aparecer em codificações diferentes. O modelo de embeddings recebe o texto como está; duas codificações distintas do mesmo conteúdo tendem a gerar vetores parecidos, mas não iguais, e a diferença atrapalha buscas por igualdade e comparações exatas. Normalize antes de indexar e mantenha a mesma forma em consulta.

Remover o espaço não separável pode quebrar alguma coisa?

Só a aparência de quebra de linha naquele ponto, o que raramente importa em dados processados por IA. O ganho em comparação e busca compensa. Se precisar exibir o texto depois, o layout pode ser refeito na apresentação.

Como sei qual forma de normalização o sistema de destino espera?

Confira a documentação do sistema ou do fornecedor. Quando não há indicação, NFC é a escolha segura para texto geral. Para campos que funcionam como identificador, NFKC costuma ser a escolha certa, exatamente como recomenda o FAQ oficial da Unicode.

Dá para fazer essa limpeza sem programar?

Para poucos arquivos, um editor que mostra caracteres invisíveis e permite localizar e substituir resolve. Para catálogos e bases com muitos arquivos, um script de varredura e limpeza é mais confiável e reprodutível, e evita depender de quem lembra de conferir na mão.

Isso tem relação com a acentuação do português?

Tem. Nomes com acento podem vir como caractere único ou como letra mais acento combinante. As duas formas são canonicamente equivalentes, mas não são iguais byte a byte. Normalizar coloca tudo numa forma só.

Fontes e leitura recomendada

Sobre

A Redação IA Mágica é formada por especialistas e pesquisadores em inteligência artificial aplicada, agentes autônomos, automações no-code/pro-code e grandes modelos de linguagem (LLMs). Nossos conteúdos cobrem implementações reais, análises e tutoriais aprofundados para profissionais e empresas.