Desfaz o espaçamento entre letras com sed

4

Eu tenho um arquivo de texto fonte contendo texto onde algumas palavras são como a palavra "letterpaced" nesta pergunta (ou seja, há um caractere de espaço entre as letras da palavra.

Como posso desfazer o espaçamento entre letras usando sed?

Um padrão como \{[A-Za-z] \}+[A-Za-z] captura uma palavra espaçada e s/ //g retira os espaços, mas como extrai uma palavra espaçada de letras de uma linha de texto e desfaz o espaçamento de letras sem prejudicar os caracteres de espaço legítimos no restante o texto?

    
por jknappen 03.07.2015 / 17:07

3 respostas

5

Você pode fazer assim:

sed     -e's/ \([^ ][^ ]\)/\n/g' \
        -e's/\([^ ][^ ]\) /\n/g' \
        -e's/ //g;y/\n/ /
'       <<\IN
I have a source text file containing text where
some words are l e t t e r s p a c e d
like the word "letterspaced" in this question
(i.e., there is a space character between the
letters of the word. 
IN

A idéia é primeiro encontrar todos os espaços que são precedidos ou seguidos por dois ou mais caracteres não-espaciais e os separam como caracteres de nova linha. Em seguida, basta remover todos os espaços restantes. E por último, traduza todas as novas linhas de volta para espaços.

Isso não é perfeito - sem incorporar um dicionário inteiro de cada palavra que você poderia usar, o melhor que você obterá é algum tipo de heurística. Este é muito bom, apesar de tudo.

Além disso, dependendo do sed que você usa, talvez seja necessário usar uma nova linha literal no lugar do n que também uso nas duas primeiras instruções de substituição.

Afora essa ressalva, no entanto, isso funcionará - e funcionará muito rápido - com qualquer POSIX sed . Ele não precisa fazer qualquer lookaheads ou behinds caros, porque ele simplesmente salva impossibles, o que significa que ele pode manipular todo o espaço padrão para cada substituição em um único endereço.

OUTPUT

I have a source text file containing text where some
words are letterspaced
like the word "letterspaced" in this question
(i.e., there is a space character between the
letters of the word.
    
por 03.07.2015 / 18:41
3

Uma abordagem Perl que funciona principalmente:

perl -C -lpe 's/(?:^|\P{L})\K\p{L}(?:\s\p{L})+(?=\P{L}|$)/$&=~s{\s}{}rgo/goe'

Isso pressupõe uma versão do Perl recente o suficiente para saber sobre o sinalizador /r nas substituições.

Prova de conceito:

$ echo  'Do I like «ł é t t ê r s p ä c è đ» text?' | perl -C -lpe 's/(?:^|\P{L})\K\p{L}(?:\s\p{L})+(?=\P{L}|$)/$&=~s{\s}{}rgo/goe'
Do I like «łéttêrspäcèđ» text?
    
por 03.07.2015 / 17:51
0

As asserções antecipadas de Perl simplificam isso. AFAIK, sed não tem estes.

Dado que dois ou mais espaços em branco separam as palavras, isso elimina espaços simples, mas deixa sequências inalteradas de dois ou mais:

perl -pe 's/\s(?!\s)//g' myfile

A opção p faz o Perl ler myfile e, em seguida, substitui espaços únicos ( \s ) que NÃO são seguidos por outro espaço. Esta é a afirmação de lookahead negativa dada por (?!\s) .

    
por 03.07.2015 / 17:50