É possível com o Gedit ou a linha de comando modificar cada quarta linha de um arquivo de texto?

11

Estou tentando converter um arquivo de texto em uma planilha separada por guias. Meu arquivo de texto é algo assim:

Dog
Cat
Fish
Lizard
Wolf
Lion
Shark
Gecko
Coyote
Puma
Eel
Iguana

Com as funções padrão de pesquisa e substituição no Gedit ou no LibreOffice, é fácil substituir o fim de linha por uma guia. Mas se eu apenas trocar retornos de carro por abas, eu vou pegar isso:

Dog   Cat   Fish   Lizard   Wolf   Lion   Shark   Gecko   Coyote   Puma   Eel   Iguana

Mas o que eu preciso fazer é que fique assim:

Dog   Cat   Fish   Lizard
Wolf   Lion   Shark   Gecko  
Coyote   Puma   Eel   Iguana

Então, posso trocar cada caractere de fim de linha por uma guia exceto para cada quarta linha?

Eu não sei se esse tipo de iteração condicional pode ser feito com expressões regulares dentro de um programa como o Gedit ou o LibreOffice, então talvez isso deva ser algum tipo de função de linha de comando? Não estou nem certo sobre qual é a melhor ferramenta para começar.

Atualização:

Eu tentei os seguintes comandos:

sed 'N;N;N;s/\n/\t/g' file > file.tsv

paste - - - - < file > file.tsv

pr -aT -s$'\t' -4 file > file.tsv

xargs -d '\n' -n4 < inputfile.txt

Mas quando tento abrir o arquivo tsv resultante no LibreOffice, as colunas não estão corretas. Não tenho certeza se isso significa que não estou executando os comandos acima corretamente ou se estou fazendo algo errado na função de importação do LibreOffice:

Apenasparareferência,oresultadodesejadodeveserassim:

    
por Questioner 25.04.2018 / 14:00

8 respostas

16

Você poderia usar um editor de linha de comando, como sed

sed 'N;N;N;s/\n/\t/g' file > file.tsv

ou, mais programaticamente, adicionando caracteres de continuação de linha invertidos a cada uma das linhas que você deseja unir usando o operador de n skip m endereço do GNU sed e seguindo-o com o clássico one-liner para unir continuação linhas:

sed '0~4! s/$/\t\/' file | sed -e :a -e '/\$/N; s/\\n//; ta'

Veja, por exemplo, Sed-liners explicados :

  1. Append a line to the next if it ends with a backslash "\".

    sed -e :a -e '/\$/N; s/\\n//; ta'
    

No entanto, IMHO seria mais fácil com um dos outros utilitários de processamento de texto padrão, por exemplo

paste - - - - < file > file.tsv

(o número de - corresponderá ao número de colunas) ou

pr -aT -s$'\t' -4 file > file.tsv

(você pode omitir o -s$'\t se não se importar que a saída seja separada por várias guias).

O estranho comportamento de reimportação que você está observando é quase certamente porque o arquivo original possui terminações de linha CRLF no estilo Windows. Se você precisar trabalhar com arquivos do Windows, poderá rolar a conversão para o comando de várias maneiras, por exemplo,

tr -d '\r' < file.csv | paste - - - -

ou

sed 'N;N;N;s/\r\n/\t/g' file.csv

O primeiro removerá TODOS os retornos de carro, enquanto o segundo preservará um CR no final de cada uma das novas linhas (que pode ser o que você deseja se o usuário final estiver no Windows).

    
por steeldriver 25.04.2018 / 14:07
13

Você pode usar xargs para agrupar sempre quatro linhas em uma, separadas por um único espaço cada:

xargs -d '\n' -n4 < inputfile.txt

-d '\n' define o delimitador de entrada como um caractere de nova linha, caso contrário, ele também seria quebrado em espaços. Se você tiver apenas uma palavra por linha de entrada, você pode até mesmo omitir isso.
-n4 define o número do argumento (o número de itens de entrada por linha de saída) como 4.

Saída:

Dog Cat Fish Lizard
Wolf Lion Shark Gecko
Coyote Puma Eel Iguana

Ou se você quiser separadores como separadores em vez de um espaço, poderá substituí-los depois. No entanto, se você tivesse espaços em suas linhas de entrada, eles também seriam substituídos:

xargs -d '\n' -n4 | tr ' ' '\t'

Saída (veja dependendo da largura da guia do navegador / terminal):

Dog Cat Fish    Lizard
Wolf    Lion    Shark   Gecko
Coyote  Puma    Eel Iguana
    
por Byte Commander 25.04.2018 / 14:19
3

Você também pode usar:

awk -v ORS="" '{print $1; print NR%4==0?"\n":"\t"}' file > file.tsv 

As duas variáveis internas awk são:

  • ORS : O utput R ecord S eparador (padrão = nova linha). É adicionado no final de cada comando de impressão.
  • NR : N N do aw atual R está processando.

Este comando irá, para cada linha, exibir o conteúdo da primeira coluna (e aqui apenas). Em seguida, escolha adicionar uma nova linha ou uma guia testando o restante da divisão de NR por 4.

    
por arauk 25.04.2018 / 20:07
3

Outra abordagem de awk mais curta:

awk '{printf $0 (NR%4?"\t":"\n")}' infile

Esta printf é a única coluna seguida por next e next e ... e um caractere Tab \t após cada um, mas printf um caractere \n ewline quando N umber de R ecord foi fator de 4 (onde NR%4 retornará 0 (false) que é o que o Operador Ternário condition(s)?when-true:when-false está fazendo.)

    
por devWeek 26.04.2018 / 06:59
3

Minha solução para isso seria usar a combinação de sed e sed . Primeiro, você poderia marcar cada quarta linha com algum caractere especial, por exemplo > , usando esta solução:

Neste caso, você quer começar a partir da linha 5 e marcar cada quarta linha depois dela. No% GNUsed que pode ser fornecido como um endereço 5~4 . Você pode usar este comando:

sed '5~4s/^/>/' file1 > file2

Em seguida, você precisa remover as novas linhas, o que pode ser feito com um sed loop:

sed ':a;N;s/\n/ /;ba' file2 > file3

Existem maneiras mais fáceis de converter novas linhas em algum outro caractere, por exemplo, com tr :

tr '\n' ' ' < file2 > file3

De qualquer forma, combinando os dois dá

Dog   Cat   Fish   Lizard   >Wolf   Lion   Shark   Gecko   >Coyote   Puma   Eel   Iguana

(a versão sed deixa uma nova linha à direita, enquanto a versão tr não)

Depois disso, você só precisa converter os caracteres especiais inseridos em novas linhas; veja por exemplo Converta um arquivo delimitado por tabulação para usar novas linhas . Nesse caso, altere > para novas linhas:

sed 'y/>/\n/' file3 > outfile

O comando y executa a mesma função que tr , transformando um caractere em outro, mas você pode usar o comando s aqui igualmente bem. Com s , você precisa de g para operar em cada correspondência na linha ( sed 's/>/\n/g' ).

Em vez de criar dois arquivos intermediários, você pode usar pipes:

$ sed '5~4s/^/>/' file | sed ':a;N;s/\n/ /;ba' | sed 'y/>/\n/'
Dog Cat Fish Lizard 
Wolf Lion Shark Gecko 
Coyote Puma Eel Iguana

Se espaços à direita forem um problema, você pode adicionar outro comando para removê-los:

| sed 's/ $//'
    
por spaceman117X 25.04.2018 / 14:26
2

Por uma questão de "completude" aqui está uma solução pura:

#!/usr/bin/env bash

sep=$'\t'

while read one \
      && read two \
      && read three \
      && read four
do
  printf "%s\n" "$one$sep$two$sep$three$sep$four"
done

Funciona também com espaços, supondo que IFS esteja configurado corretamente (que deve, por padrão, AFAIK). Além disso, acho que isso pode até ser um script de shell portátil e funcionar com qualquer shell compatível com POSIX.

    
por Daniel Jour 25.04.2018 / 19:31
2

Uma macro vim (gravada com q) pode aplicar sua operação e, em seguida, pular três linhas. Então, você acabou de executar essa macro n vezes.

por exemplo:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q
    
por rackandboneman 26.04.2018 / 00:10
2

Já que você pediu por uma solução Gedit, algo assim deveria funcionar:

Encontrar:

(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+

Substitua por:

\t\t\t\n

Verifique se a caixa de seleção das expressões regulares está marcada.

Como funciona:

O primeiro passo é encontrar uma série de caracteres de palavras, com \ w +, e capturar os resultados na variável \ 1 ao colocar parênteses em volta da expressão:

(\w+)

Em seguida, procuramos por uma série de caracteres finais de linha, \ r e \ n, ou CR e LF. Como os arquivos formatados do Windows usam ambos, criamos uma classe de caractere agrupando esses dois caracteres entre colchetes. O sinal de adição faz com que ele pesquise um ou mais caracteres:

[\r\n]+

Finalmente, repetimos isso mais 3 vezes, armazenando cada palavra subseqüente nas variáveis \ 2, \ 3 e \ 4. Isso faz com que nosso substituir com expressão simples. Precisamos colocar caracteres de tabulação, \ t e um novo caractere de linha, \ n, nos locais apropriados para a formatação de que você precisa.

    
por Jason Wood 26.04.2018 / 06:33