Limpar uma lista colada de uma folha de cálculo ou de um PDF
Publicado a 06/08/2026 · 12 min de leitura · Ferramentas de texto e idioma
Daniel Okonkwo — Programador front-end e redator de Tecnologia na OneKitly
Desempenho web · Formatos de ficheiro
Verificado a partir de 4 fontes
Passe primeiro o trim-lines e depois o remove-blank-lines. A ordem importa porque o remove-blank-lines decide o que está vazio com o .trim() do JavaScript, que trata mesmo U+00A0 (espaço inquebrável) como espaço, mas não toca no texto das linhas que mantém: uma linha «Lyon » sobrevive com os três espaços finais intactos. O trim-lines usa o mesmo .trim() e limpa as duas pontas de cada linha, incluindo um retorno de carro solto. Entre os dois cobrem espaços, tabulações, espaços inquebráveis, espaços finos e a marca de ordem de bytes. Dois carateres escapam-lhes: U+00AD, o hífen condicional que um PDF insere onde partiu uma palavra no fim da linha, e U+200B, o espaço de largura nula. Nenhum é espaço para o JavaScript, pelo que atravessam remove-blank-lines, trim-lines, trailing-whitespace-remover e remove-whitespace sem alteração. Vigie sobretudo o trailing-whitespace-remover: só reconhece o espaço ASCII e a tabulação, portanto sobre a string «x» seguida de um espaço inquebrável não muda nada, e sobre «x» + inquebrável + espaço normal retira o normal e deixa o inquebrável. As quatro ferramentas reescrevem também em silêncio os finais de linha CRLF como quebras simples, o que costuma ser o pretendido, e nenhuma considera quebra de linha um retorno de carro solto. Uma colagem de folha de cálculo traz ainda tabulações entre as células de uma linha: o remove-whitespace com as definições por omissão apagará essas tabulações e colará as suas colunas umas às outras.
Uma colagem transporta carateres invisíveis: espaços inquebráveis, hífenes condicionais, espaços de largura nula, tabulações e CRLF. Quatro ferramentas de limpeza foram passadas por cada um, e usam três definições diferentes de espaço.
O que chega realmente à área de transferência
O texto que vê no ecrã e o texto da área de transferência não são o mesmo objeto. Um PDF não tem linhas nem parágrafos: tem caixas de glifos em coordenadas. Quando seleciona uma coluna de texto e a copia, o leitor reconstrói uma ordem de leitura plausível e insere uma quebra de linha no fim de cada caixa, pelo que uma frase que ocupava três linhas impressas chega em três linhas. Se o compositor partiu uma palavra num desses fins de linha, uns produtores escrevem um hífen verdadeiro e outros U+00AD, o hífen condicional, que se desenha como hífen só se ali cair um corte e como nada nos restantes casos. E como a maioria dos PDF europeus é composta com espaços inquebráveis antes dos dois pontos, dos pontos e vírgulas e das unidades, um documento francês ou italiano entrega-lhe U+00A0 onde juraria haver espaços normais.
Uma colagem de folha de cálculo é mais arrumada, mas não limpa. Excel, Numbers e Google Sheets colocam todos uma tabulação entre as células de uma linha e uma quebra de linha entre linhas, e no Windows essa quebra é um CRLF: um retorno de carro seguido de um avanço de linha, dois carateres onde vê um. Apague um bloco de linhas no meio de uma seleção e muitas vezes copia também as linhas vazias, que chegam como linhas contendo apenas tabulações. É essa a forma para a qual as ferramentas desta página foram feitas: uma lista em que as linhas úteis estão separadas por linhas que só contêm carateres invisíveis, e em que algumas linhas úteis carregam carateres invisíveis próprios numa das pontas ou nas duas.
Quatro ferramentas, três definições de espaço
O remove-blank-lines e o trim-lines chamam ambos o .trim() do JavaScript. A linguagem define o que isso remove como WhiteSpace mais LineTerminator, e WhiteSpace inclui todos os carateres da categoria Unicode Space_Separator — onde vivem U+00A0, U+2009 (espaço fino) e U+202F (espaço fino inquebrável) — mais a marca de ordem de bytes U+FEFF. Coloque cada um desses carateres sozinho numa linha e passe pelo remove-blank-lines: a linha desaparece. O remove-whitespace usa a classe de expressão regular \s, que designa o mesmo conjunto. Três das quatro ferramentas concordam, portanto, sobre o espaço inquebrável, e concordam com o que quem lê esperaria.
O trailing-whitespace-remover não. O seu padrão é uma sequência de espaço ASCII ou tabulação ancorada ao fim da linha, e mais nada conta. Alimentado com a string x seguida de um espaço inquebrável, devolve a string inalterada. Alimentado com x seguido de um inquebrável e depois de um espaço normal, retira o normal e devolve x mais o inquebrável: visualmente não encurtou nada, e continua a não ser igual a x. Não é uma diferença cosmética. Se limpa uma lista antes de lhe tirar duplicados, é esse espaço inquebrável sobrevivente que mantém separados dois nomes de cidade idênticos.
Os dois carateres que nenhuma destas ferramentas remove
U+00AD, o hífen condicional, e U+200B, o espaço de largura nula, não são espaços para o JavaScript. A classe de expressão regular \s não os reconhece e o .trim() não os remove, o que foi verificado diretamente em vez de assumido. Assim, uma linha que contenha apenas um hífen condicional sobrevive ao remove-blank-lines e parece, na caixa de saída, exatamente uma linha vazia que a ferramenta se recusou a apagar. A palavra «cooperativas» copiada de um PDF com hifenização, com um hífen condicional entre «co» e «operativas», sai idêntica das quatro ferramentas — e nunca corresponderá à string «cooperativas» em nenhuma pesquisa que faça depois.
Há uma única ferramenta neste site que os apaga mesmo, e a troca é má para cinco das nossas seis línguas. O remove-non-ascii retira todo o carácter acima de U+007F, o que leva de facto o hífen condicional, o espaço de largura nula, o espaço inquebrável e a marca de ordem de bytes. Leva também pura e simplesmente cada letra acentuada em vez de a dobrar: a frase «Les coopératives régionales», passada com um hífen condicional dentro da primeira palavra, saiu «Les coopratives rgionales» — o e acentuado pura e simplesmente desaparecido, não substituído por um sem acento. A via honesta é o find-and-replace com o carácter culpado colado no campo «Localizar», que funciona porque essa ferramenta faz escape ao termo de pesquisa e o compara literalmente. Resta arranjar um exemplar de um carácter invisível, o que é exatamente tão incómodo quanto parece.
Finais de linha, e a única quebra que estas ferramentas não veem
As quatro ferramentas dividem num avanço de linha precedido de um retorno de carro opcional, e depois voltam a juntar o resultado com avanços simples. Isso significa que todas normalizam os finais CRLF do Windows para quebras Unix como efeito secundário, faça o que fizer além disso: cole um bloco de folha de cálculo, passe o remove-blank-lines, e a saída fica um byte mais curta por linha mesmo que nenhuma linha tenha sido removida. É quase sempre o que queria, mas vale a pena saber que aconteceu, porque um ficheiro que depois tenha de voltar a uma ferramenta Windows pode precisar que lhe devolvam os finais.
A quebra que não veem é um retorno de carro solitário, sem avanço de linha atrás — o final de linha do Mac OS clássico até 2001, e o que algumas rotinas de exportação antigas e certos despejos de bases de dados ainda emitem. Perante os três carateres a, retorno de carro, retorno de carro, b, as quatro ferramentas tratam o conjunto como uma só linha e devolvem-no intacto. Nada o avisa. Se uma colagem volta como uma única linha enorme sem quebras visíveis e sem erro, é a primeira coisa a suspeitar, e o remédio é abrir o ficheiro num editor capaz de converter finais de linha antes de o trazer para aqui.
A ordem por que as encadear
trim-lines primeiro, remove-blank-lines depois. A ordem inversa dá o mesmo resultado na maioria das entradas, porque o remove-blank-lines já testa cada linha com .trim() antes de decidir: uma linha de três espaços cai quer tenha aparado antes quer não. Verificado sobre a entrada desarrumada «dois espaços, alpha, dois espaços», depois uma linha só de tabulação, depois «dois espaços, beta, um espaço», depois uma linha vazia, depois «alpha»: ambas as ordens produziram alpha, beta, alpha. A razão para pôr o trim-lines primeiro de qualquer modo é o que vem a seguir. Dê essa mesma entrada ao duplicate-line-finder sem a ter aparado e ele não assinala duplicado nenhum, porque o primeiro alpha leva dois espaços à frente e dois atrás. Dê-lhe a versão aparada e ele assinala alpha.
Duas coisas a não fazer. Não recorra ao remove-whitespace sobre uma colagem de folha de cálculo se não tiver decidido que as colunas podem desaparecer: com a definição por omissão apaga todo o espaço, tabulação e quebra de linha, e a linha de cabeçalho «Nom, tabulação, Ville, tabulação, CA» saiu «NomVilleCA». Ligar «manter quebras de linha» preserva as linhas mas continua a comer as tabulações, portanto as colunas continuam coladas. E não passe o trailing-whitespace-remover à espera de que torne duas linhas comparáveis: retira o espaço ASCII e a tabulação, e mais nada, que era todo o assunto da segunda secção. Quando o objetivo é comparar e não arrumar, é o trim-lines que fecha a diferença.
| Entrada | O que acontece | Porquê |
|---|---|---|
| Uma linha de três espaços normais, no remove-blank-lines | Removida | O teste é linha.trim().length > 0, e o .trim() esvazia-a |
| Uma linha contendo apenas U+00A0, no remove-blank-lines | Removida | O WhiteSpace do ECMAScript cobre toda a categoria Space_Separator |
| Uma linha contendo apenas U+00AD, no remove-blank-lines | Mantida, e parece vazia na saída | O hífen condicional é da categoria Cf, um carácter de formatação, não um espaço |
| x seguido de um U+00A0, no trailing-whitespace-remover | Devolvido inalterado | O seu padrão é uma sequência de espaço ASCII ou tabulação no fim da linha, nada mais amplo |
| x, depois U+00A0, depois um espaço normal, no trailing-whitespace-remover | Volta como x seguido de U+00A0 | A sequência de espaços ASCII para no primeiro carácter fora da classe |
| O mesmo x mais U+00A0, no trim-lines | Volta como x | O mesmo .trim() do remove-blank-lines, aplicado ao texto em vez do teste |
| A linha de cabeçalho Nom, tabulação, Ville, tabulação, CA, no remove-whitespace | NomVilleCA — as colunas desapareceram | Uma tabulação é espaço, e «manter quebras de linha» só poupa a quebra de linha |
| a, retorno de carro, retorno de carro, b — em qualquer das quatro | Tratado como uma só linha, devolvido intacto | Todas dividem num avanço de linha precedido de um retorno de carro opcional |
Perguntas frequentes
- Porque é que a minha lista continua com linhas de aspeto vazio depois do remove-blank-lines?
- É quase de certeza um espaço de largura nula (U+200B) ou um hífen condicional (U+00AD) sozinho na linha. Nenhum é espaço para o JavaScript, portanto o teste da ferramenta — sobra alguma coisa depois do .trim()? — responde que sim e a linha fica. Ambos foram passados pela ferramenta para o confirmar. Um espaço inquebrável ou um espaço fino sozinhos teriam sido removidos, logo a linha sobrevivente não é um desses. Para identificar o carácter sem adivinhar, cole a linha num contador de carateres ou de bytes e veja que a contagem é um e não zero.
- Então o trailing-whitespace-remover está avariado?
- Faz o que a sua própria descrição anuncia — remover espaços e tabulações no fim da linha — e essa definição estreita é a certa para o seu trabalho habitual: limpar o lixo invisível no fim das linhas de código antes de um commit. As ferramentas de diff e os linters ocupam-se do espaço ASCII e da tabulação; um espaço inquebrável dentro de código é um erro que quer ver, não um que queira apagado em silêncio. O único problema é que o nome se lê como uma promessa geral. Para prosa e para listas coladas de documentos, o trim-lines é a ferramenta de definição ampla, e é a que se deve usar quando duas linhas têm depois de comparar como iguais.
- Como me livro dos hífenes condicionais que um PDF meteu no meu texto?
- Nenhuma das quatro ferramentas deste artigo o fará. O find-and-replace fará, se conseguir meter um hífen condicional no campo «Localizar»: a ferramenta faz escape ao que escrever e compara-o literalmente, o que foi verificado, portanto colar o carácter funciona e escrever uma descrição dele não. Arranjar um exemplar de um carácter invisível costuma passar por selecionar um vão suspeitosamente largo no texto de origem com as setas e Shift, e copiá-lo. O remove-non-ascii também os remove, mas leva com eles cada letra acentuada sem a substituir: sobre texto francês, espanhol, português, alemão ou italiano destrói mais do que conserta.
- Alguma coisa disto envia a minha lista para um servidor?
- Não. As quatro transformações são operações de string correntes que correm na página que tem aberta, sobre o texto da caixa, e produzem a saída na mesma página. Nada na natureza do trabalho exige um servidor: dividir nas quebras de linha e testar cada linha são umas poucas linhas de código, e não há dicionário nem modelo a consultar. Aqui isso importa mais do que o habitual, porque as listas que se limpam assim vêm muitas vezes de documentos internos — nomes de clientes, referências de encomendas, mapas de pessoal — e colar uma numa ferramenta que a envia é uma decisão de transferência de dados, não de formatação.
- A minha colagem de folha de cálculo mantém as tabulações. Como obtenho um item por linha?
- Nenhuma das quatro faz isso, e o remove-whitespace faz mesmo o contrário: apaga as tabulações e solda as células umas às outras, o que foi verificado numa linha de cabeçalho de três colunas que voltou como uma só palavra. Se só queria uma coluna, copie uma única coluna da folha: a colagem não conterá tabulação alguma e o remove-blank-lines mais o trim-lines bastam. Se tem várias colunas e as quer empilhadas uma por linha, essa é outra operação com a sua própria ferramenta, e a resposta honesta é que estas quatro limpam linhas, não partem colunas.
Artigos que podem interessar-lhe
Todos os guias →Ferramentas relacionadas
Tudo o que se segue descreve o que estas ferramentas fazem hoje, verificado executando as suas próprias transformações sobre as entradas exatas reproduzidas em cada artigo, e não o que uma norma obrigue uma ferramenta de texto a fazer. O tratamento do texto linha a linha não tem autoridade única: o que conta como espaço, se duas linhas acentuadas são ou não a mesma linha, e onde termina um URL dentro de uma frase são decididos de forma diferente por cada programa onde colar texto. Quando uma ferramenta erra num caso, isso é dito com franqueza em vez de contornado. Antes de passar qualquer disto por uma lista que não possa reexportar, passe por uma cópia e compare o número de linhas nas duas pontas.
Fontes
- Ecma International — ECMAScript Language Specification — WhiteSpace and String.prototype.trim
- Unicode Consortium — Unicode Character Database — PropList.txt (White_Space property)
- Unicode Consortium — UAX #14: Unicode Line Breaking Algorithm (soft hyphen, class BA)
- MDN Web Docs — Regular expressions — character class escape (\s)
Detetaste um erro neste artigo?