Czy za pomocą Gedit lub wiersza poleceń można modyfikować co czwarty wiersz pliku tekstowego?

11

Próbuję przekonwertować plik tekstowy na arkusz kalkulacyjny oddzielony tabulatorami. Mój plik tekstowy wygląda mniej więcej tak:

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

Dzięki standardowym funkcjom wyszukiwania i zamiany w Gedit lub LibreOffice łatwo zastąpić koniec linii tabulatorem. Ale jeśli po prostu zamienię zwrot karetki na tabulatory, otrzymam to:

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

Ale muszę to zrobić tak:

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

Czy mogę zamienić każdy znak końca linii na tabulator oprócz każdej czwartej linii?

Nie wiem, czy tego rodzaju warunkową iterację można wykonać za pomocą wyrażeń regularnych w programie takim jak Gedit lub LibreOffice, więc może to musi być jakaś funkcja wiersza poleceń? Nie jestem nawet pewien, jakie jest najlepsze narzędzie na początek.


Aktualizacja:

Próbowałem następujących poleceń:

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

Ale kiedy próbuję otworzyć wynikowy tsvplik w LibreOffice, kolumny nie są w porządku. Nie jestem pewien, czy to oznacza, że ​​nie wykonuję poprawnie powyższych poleceń, czy też robię coś złego w funkcji importu LibreOffice:

Otwarcie TSV w Calc

Dla porównania pożądany wynik powinien wyglądać następująco:

Właściwe kolumny

Indagator
źródło

Odpowiedzi:

16

Ty mógł użyć edytora wiersza polecenia, takie jaksed

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

lub, bardziej programowo, dodając znaki kontynuacji linii z odwrotnym ukośnikiem do każdej linii, do której chcesz się połączyć, używając n skip moperatora adresu GNU sed i podążając za nią z klasycznym jednowierszowym do łączenia ciągłych linii:

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

Zobacz na przykład wyjaśnienie Sed One-Liners :

  1. Dodaj wiersz do następnego, jeśli kończy się odwrotnym ukośnikiem „\”.

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

Jednak IMHO byłoby łatwiejsze dzięki innym standardowym narzędziom do przetwarzania tekstu, np

paste - - - - < file > file.tsv

(liczba -będzie odpowiadać liczbie kolumn) lub

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

(możesz pominąć, -s$'\tjeśli nie przeszkadza ci to, że dane wyjściowe zostaną rozdzielone wieloma kartami).


Dziwne zachowanie podczas ponownego importowania, które obserwujesz, jest prawie na pewno, ponieważ oryginalny plik ma zakończenia linii CRLF w stylu Windows. Jeśli potrzebujesz pracować z plikami z systemu Windows, możesz przekształcić konwersję do polecenia na różne sposoby, np

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

lub

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

Pierwszy usunie WSZYSTKIE zwroty karetki, a drugi zachowa CR na końcu każdej z nowych linii (co może być tym, czego chcesz, jeśli zamierzony użytkownik końcowy jest w systemie Windows).

steeldriver
źródło
1
Uwaga na temat zakończeń linii w stylu Windows: standardowymi narzędziami do konwersji między nimi a stylem uniksowym są dos2unixi unix2dos.
David Foerster,
13

Możesz użyć, xargsaby zawsze zgrupować cztery linie w jeden, oddzielone pojedynczą spacją:

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

-d '\n'ustawia ogranicznik wejściowy na znak nowego wiersza, w przeciwnym razie łamałby się również na spacjach. Jeśli i tak masz tylko jedno słowo w wierszu wprowadzania, możesz nawet to pominąć.
-n4ustawia liczbę argumentów (liczbę elementów wejściowych na linię wyjściową) na 4.

Wynik:

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

Lub jeśli chcesz tabulatory jako separatory zamiast spacji, możesz je później wymienić. Jeśli jednak w wierszach wejściowych byłyby spacje, zostaną one również zastąpione:

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

Dane wyjściowe (wygląd w zależności od szerokości zakładki przeglądarki / terminala):

Dog Cat Fish    Lizard
Wolf    Lion    Shark   Gecko
Coyote  Puma    Eel Iguana
Bajt Dowódca
źródło
Ta metoda ma tę zaletę, że zachowuje się rozsądnie, nawet jeśli całkowita liczba linii wejściowych nie jest wielokrotnością czterech.
Eliah Kagan,
3

Możesz również użyć:

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

Dwie wbudowane zmienne awk to:

  • ORS: O utput R ecord S eparator (domyślnie = nowy wiersz). Jest dodawany na końcu każdego polecenia drukowania.
  • NR: N umbra obecnego R ow awk przetwarzania.

To polecenie wyświetli dla każdej linii zawartość pierwszej (i tylko tutaj) kolumny. Następnie wybiera dodanie nowego wiersza lub karty, testując pozostałą część podziału NRprzez 4.

arauk
źródło
3

Kolejne najkrótsze awkpodejście:

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

Ten printf tylko jedną kolumnę, a następnie przez następne i następne i ... i zakładkę \tznak po sobie, ale printf do \ncharakteru ewline gdy N umbra z R ECORD był czynnikiem 4 (gdzie NR%4zwróci 0 (fałsz), który jest co Ternary Operator condition(s)?when-true:when-falseto robi.)

αғsнιη
źródło
3

Moim rozwiązaniem byłoby użycie kombinacji sedi sed. Po pierwsze, co czwarty wiersz można oznaczyć znakiem specjalnym, na przykład >za pomocą tego rozwiązania:

W takim przypadku chcesz zacząć od linii 5 i zaznaczać co 4 linię po niej. W GNU sedmożna to podać jako adres 5~4. Możesz użyć tego polecenia:

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

Następnie musisz usunąć nowe linie, co można zrobić za pomocą sedpętli:

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

Są łatwiejsze sposoby konwersji znaków nowej linii na inny znak, na przykład za pomocą tr:

tr '\n' ' ' < file2 > file3

Tak czy inaczej, połączenie tych dwóch daje

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

( sedwersja pozostawia końcowy znak nowej linii, a trwersja nie)

Następnie wystarczy przekonwertować wstawione znaki specjalne na znaki nowej linii; patrz na przykład Konwertuj plik rozdzielany tabulatorami, aby używać znaków nowej linii . W takim przypadku zmień >na nowe linie:

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

yPolecenie wykonuje tę samą funkcję, co tr, przekształcając jednego znaku do drugiego, ale można użyć skomendy tutaj równie dobrze. Za pomocą smusisz goperować każdym dopasowaniem w linii ( sed 's/>/\n/g').

Zamiast tworzyć dwa pliki pośrednie, możesz użyć potoków:

$ 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

Jeśli końcowe spacje stanowią problem, możesz dodać kolejne polecenie, aby je usunąć:

| sed 's/ $//'
spaceman117X
źródło
2

Dla "kompletności" oto czyste rozwiązanie 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

Działa również ze spacjami, przy założeniu, że IFSjest poprawnie ustawiony (który powinien domyślnie AFAIK). Co więcej, myślę, że może to być nawet przenośny skrypt powłoki i działać z dowolną powłoką kompatybilną z POSIX.

Daniel Jour
źródło
1
Nie jest to ogólnie rzecz biorąc przenośne dla powłok kompatybilnych z POSIX, ponieważ $' 'POSIX nie wymaga formy cytowania. Na przykład w dash(który shdomyślnie zapewnia w Ubuntu), uruchamianie printf '%s\n' $'a\tb'tylko wyjść $a\tb. To nie znaczy, że to nie jest przydatne; to działa w trybie bash. Jednak, podobnie jak w przypadku niektórych innych rozwiązań opublikowanych przez ludzi, produkuje niepełne dane wyjściowe, jeśli liczba wierszy danych wejściowych nie jest wielokrotnością czterech. Polecam również użycie read -r, ponieważ nie ma powodu, aby sądzić, że pożądane jest tutaj rozwinięcie ukośników odwrotnych w pliku wejściowym.
Eliah Kagan,
Możesz po prostu zrobićprintf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
terdon
2

Makro vim (zapisane za pomocą q) może zastosować operację, a następnie pominąć trzy linie. Następnie wystarczy uruchomić to makro n razy.

na przykład:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q
rackandboneman
źródło
2

Ponieważ poprosiłeś o rozwiązanie Gedit, coś takiego powinno działać:

Odnaleźć:

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

Zamienić:

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

Upewnij się, że pole wyboru dla wyrażeń regularnych jest zaznaczone.

Jak to działa:

Pierwszym krokiem jest znalezienie serii znaków słownych za pomocą \ w + i przechwycenie wyników w zmiennej \ 1 przez zawinięcie nawiasów wokół wyrażenia:

(\w+)

Następnie szukamy serii znaków kończących wiersze, \ r i \ n, lub CR i LF. Ponieważ pliki sformatowane w systemie Windows używają obu, tworzymy klasę znaków, zawijając te dwa znaki w nawiasach kwadratowych. Plus powoduje, że wyszukuje jeden lub więcej znaków:

[\r\n]+

Na koniec powtarzamy to jeszcze 3 razy, przechowując każde kolejne słowo w zmiennych \ 2, \ 3 i \ 4. To sprawia, że ​​zastąpienie wyrażeniem jest proste. Musimy po prostu umieścić znaki tabulacji, \ t oraz nowy znak wiersza, \ n, w odpowiednich miejscach dla potrzebnego formatowania.

Jason Wood
źródło