È possibile con Gedit o la riga di comando modificare ogni quarta riga di un file di testo?


11

Sto cercando di convertire un file di testo in un foglio di calcolo separato da tabulazioni. Il mio file di testo è simile al seguente:

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

Con le funzioni standard di ricerca e sostituzione in Gedit o LibreOffice, è facile sostituire la fine della riga con una scheda. Ma se cambio solo i ritorni a capo con le schede, otterrò questo:

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

Ma quello che devo fare è farlo apparire così:

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

Quindi, posso scambiare ogni carattere di fine riga con una scheda tranne ogni quarta riga?

Non so se quel tipo di iterazione condizionale possa essere fatta con espressioni regolari all'interno di un programma come Gedit o LibreOffice, quindi forse questo deve essere un qualche tipo di funzione da riga di comando? Non sono nemmeno chiaro su quale sia lo strumento migliore per iniziare.


Aggiornare:

Ho provato i seguenti comandi:

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

Ma quando provo ad aprire il tsvfile risultante in LibreOffice, le colonne non sono del tutto esatte. Non sono sicuro che ciò significhi che non sto eseguendo correttamente i comandi sopra, o se sto facendo qualcosa di sbagliato nella funzione di importazione di LibreOffice:

Apertura TSV in Calc

Solo per riferimento, il risultato desiderato dovrebbe apparire così:

Colonne appropriate

Risposte:


16

È possibile utilizzare un editor della riga di comando comesed

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

o, più programmaticamente, aggiungendo caratteri di continuazione della riga di barra rovesciata a ciascuna delle linee che si desidera unire usando l' n skip moperatore di indirizzo GNU sed e seguendolo con il classico one-liner per unire le linee continue:

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

Vedi ad esempio Spiegazione di One-Liners di Sed :

  1. Aggiungi una riga alla successiva se termina con una barra rovesciata "\".

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

Tuttavia, IMHO sarebbe più semplice con una delle altre utility di elaborazione del testo standard, ad es

paste - - - - < file > file.tsv

(il numero di -corrisponderà al numero di colonne) o

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

(puoi omettere -s$'\tse non ti dispiace che l'output sia separato da più schede).


Lo strano comportamento di reimportazione che stai osservando è quasi certamente dovuto al fatto che il file originale ha terminazioni di riga CRLF in stile Windows. Se devi lavorare con file da Windows, puoi eseguire il rollback della conversione nel comando in vari modi, ad es

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

o

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

Il primo rimuoverà TUTTI i ritorni a capo mentre il secondo manterrà un CR alla fine di ciascuna delle nuove righe (che potrebbe essere quello che desideri se l'utente finale previsto è su Windows).


1
Una nota sui terminali di linea in stile Windows: gli strumenti standard per la conversione tra loro e in stile Unix sono dos2unixe unix2dos.
David Foerster,

13

Puoi usare xargsper raggruppare sempre quattro linee in una, separate da un singolo spazio ciascuna:

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

-d '\n'imposta il delimitatore di input su un carattere di nuova riga, altrimenti si spezzerebbe anche negli spazi. Se hai comunque una sola parola per riga di input, puoi persino ometterlo.
-n4imposta il numero dell'argomento (il numero di elementi di input per riga di output) su 4.

Produzione:

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

Oppure, se desideri schede come separatori anziché uno spazio, puoi sostituirle in seguito. Tuttavia, se avessi spazi nelle linee di input, anche quelle verrebbero sostituite:

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

Output (aspetto in base alla larghezza della scheda del browser / terminale):

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

Questo metodo ha il vantaggio di comportarsi in modo ragionevole anche quando il numero totale di righe di input non è un multiplo di quattro.
Eliah Kagan,

3

Puoi anche usare:

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

Le due variabili incorporate awk sono:

  • ORS: O utput R ecord S eparator (default = newline). Viene aggiunto alla fine di ogni comando di stampa.
  • NR: N umber della R ow awk corrente è in elaborazione.

Questo comando, per ogni riga, mostrerà il contenuto della prima (e solo qui) colonna. Quindi sceglie di aggiungere una nuova riga o una scheda testando il resto della divisione di NRper 4.


3

Un altro awkapproccio più breve :

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

Questo printf la sola colonna seguita da successiva e dopo e ... e di una scheda \tdi carattere dopo ogni ma printf un \ncarattere ewline quando N umero di R ECORD era fattore 4 (dove NR%4restituirà 0 (falso) che è quello ternario Operator condition(s)?when-true:when-falsesta facendo.)


3

La mia soluzione a questo sarebbe usare la combinazione di sede sed. Innanzitutto, è possibile contrassegnare ogni quarta riga con un carattere speciale, ad esempio >utilizzando questa soluzione:

In questo caso, si desidera iniziare dalla riga 5 e contrassegnare ogni 4 riga successiva. In GNU sedche può essere fornito come indirizzo 5~4. Puoi usare questo comando:

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

Quindi è necessario rimuovere le nuove righe, che possono essere eseguite con un sedciclo:

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

Esistono modi più semplici per convertire le nuove righe in qualche altro personaggio, ad esempio con tr:

tr '\n' ' ' < file2 > file3

Ad ogni modo, combinando i due dà

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

(la sedversione lascia una nuova riga finale, mentre la trversione no)

Successivamente, devi solo convertire i caratteri speciali che hai inserito in newline; vedere ad esempio Converti un file delimitato da tabulazioni per usare le nuove righe . In questo caso, passare >a newline:

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

Il ycomando svolge la stessa funzione di tr, trasformando un personaggio in un altro, ma puoi usare il scomando qui ugualmente bene. Con s, devi goperare su ogni partita nella linea ( sed 's/>/\n/g').

Invece di creare due file intermedi, puoi usare le pipe:

$ 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 gli spazi finali sono un problema, puoi aggiungere un altro comando per rimuoverli:

| sed 's/ $//'

2

Per motivi di "completezza", ecco una pura soluzione bash:

#!/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

Funziona anche con spazi, supponendo che IFSsia impostato correttamente (che dovrebbe essere predefinito, AFAIK). Inoltre, penso che questo potrebbe anche essere uno script di shell portatile e funzionare con qualsiasi shell compatibile con POSIX.


1
Questo non è portabile su shell compatibili con POSIX in generale, perché $' 'POSIX non richiede la forma di quotazione. Ad esempio, in dash(che fornisce shdi default su Ubuntu), eseguendo printf '%s\n' $'a\tb'solo output $a\tb. Ciò non significa che questo non sia utile però; funziona in bash. Tuttavia, come con alcune delle altre soluzioni che le persone hanno pubblicato, produce un output incompleto se il numero di righe di input non è un multiplo di quattro. Inoltre, ti consiglio di utilizzare read -r, poiché non vi è alcun motivo di pensare che l'espansione di escape di barra rovesciata nel file di input sia desiderata qui.
Eliah Kagan,

Potresti semplicemente farloprintf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
Terdon,

2

Una macro vim (registrata con q) potrebbe applicare l'operazione, quindi saltare tre righe. Quindi, esegui quella macro n volte.

per esempio:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q

2

Dato che hai chiesto una soluzione Gedit, qualcosa del genere dovrebbe funzionare:

Trova:

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

Sostituirlo con:

\1\t\2\t\3\t\4\n

Assicurati che la casella di controllo per le espressioni regolari sia contrassegnata.

Come funziona:

Il primo passo è trovare una serie di caratteri di parole, con \ w +, e acquisire i risultati nella variabile \ 1 avvolgendo le parentesi attorno all'espressione:

(\w+)

Quindi cerchiamo una serie di caratteri di fine riga, \ r e \ n, o CR e LF. Poiché i file formattati di Windows utilizzano entrambi, creiamo una classe di caratteri racchiudendo questi due caratteri tra parentesi quadre. Il plus consente di cercare uno o più caratteri:

[\r\n]+

Infine, lo ripetiamo altre 3 volte, memorizzando ogni parola successiva nelle variabili \ 2, \ 3 e \ 4. Questo rende semplice la nostra sostituzione con espressione. Dobbiamo solo posizionare i caratteri di tabulazione, \ t e un nuovo carattere di linea, \ n, nelle posizioni appropriate per la formattazione di cui hai bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.