urutan terbalik paragraf dalam file

8

Saya memiliki file yang berisi teks dalam paragraf (baris dengan teks dipisahkan oleh satu atau lebih baris kosong). Saya ingin membalik urutan paragraf (yaitu paragraf terakhir akan menjadi yang pertama, ...), lebih disukai dengan menggunakan sed.

Saya mencari perintah sed yang akan dilakukan untuk file paragraf, apa yang tacakan dilakukan untuk file baris.

Martin Vegter
sumber

Jawaban:

6

Penggunaan sedtidak sesederhana seperti yang disebutkan oleh Joseph R .. Namun, Anda bisa mengatakan:

sed '/./{H;d;};x;s/\n/={NL}=/g' inputfile | \
sed -e 's/^={NL}=//' -e '1!G;h;$!d' | \
sed G | sed 's/={NL}=/\'$'\n/g'

Diberikan input sampel:

Para 1 line 1
Para 1 line 2
Para 1 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 3 line 1
Para 3 line 2
Para 3 line 3

ini akan menghasilkan:

Para 3 line 1
Para 3 line 2
Para 3 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 1 line 1
Para 1 line 2
Para 1 line 3

Perlu disebutkan bahwa solusi ini (serta Perl alternatif) memerlukan baris kosong di akhir file input agar dapat bekerja seperti yang diharapkan.

devnull
sumber
6

Solusi ini menggunakan keduanya tacdan perlmembaca paragraf sekaligus. Tidak perlu membaca seluruh file ke dalam memori.

tac file | perl -00 -lpe '$_ = join "\n", reverse split /\n/'

Balikkan semua baris file, lalu untuk setiap paragraf terbalik, balikkan baris.

glenn jackman
sumber
Ini terlihat sangat elegan dan efisien. Namun, solusi ini juga mengembun beberapa garis kosong (yaitu memisahkan) menjadi satu
Martin Vegter
3

Mungkin ada cara untuk melakukan ini sed, tapi saya ragu itu akan sederhana. Inilah cara saya akan melakukannya di Perl:

perl -n00e 'push @paragraphs,$_; END{print for reverse @paragraphs}' your_file

Ini berfungsi karena mendefinisikan pemisah rekaman input sebagai karakter nol ( -00) memberitahu Perl untuk beroperasi dalam mode paragraf. Definisi Perl tentang paragraf 1 sangat cocok dengan definisi Anda.


1 Lihat di bawah judulOther values for $/

Joseph R.
sumber
ini memang berhasil. Satu-satunya masalah kecil adalah, itu tidak mempertahankan beberapa baris kosong yang memisahkan paragraf. Sebaliknya, semua paragraf dipisahkan oleh tepat satu baris kosong.
Martin Vegter
1

Jika paragraf Anda selalu dipisahkan oleh satu baris kosong:

sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed 's/^\x03//;1s/\x03$//;1!G;h;$!d;$a\' | tr $'\003' \\n

Ini cukup mudah untuk melihat cara kerjanya jika Anda memecahnya menjadi potongan-potongan dan menjalankan sed '/^$/s/^/\x02/' infilekemudian sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\ndan seterusnya ...


Jika paragraf Anda dipisahkan oleh satu atau lebih baris kosong, mis

Para 1 line 1
Para 1 line 2

Para 2 line 1


Para 3 line 1
Para 3 line 2

Para 4 line 1
Para 4 line 2



Para 5 line 1

dan Anda ingin membalik urutan paragraf tetapi mempertahankan urutan "blok kosong" Anda bisa membaca file dua kali:
1: mengubah paragraf menjadi baris tunggal (menghapus blok kosong di antara) dan membalikkannya dan
2: mengubah blok kosong menjadi satu baris, "mengindeks" jumlah baris kosong di setiap blok (dan menghapus garis tidak kosong)
kemudian pastehasil dan proses output untuk mengembalikan baris baru:

paste -d $'\004' <(sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \
<(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*/\1/}' infile) \
| sed '$!s/\x04/\n/;$s/\x04$//' | tr $'\003\002' \\n\\n

yang keluaran:

Para 5 line 1

Para 4 line 1
Para 4 line 2


Para 3 line 1
Para 3 line 2

Para 2 line 1



Para 1 line 1
Para 1 line 2

Jika Anda tidak keberatan dengan garis trailing tambahan di output, Anda bisa menghapus yang terakhir sed:

paste -d $'\n' <(sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \
<(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*/\1/}' infile) | \
tr $'\003\002' \\n\\n

Ini mengasumsikan bahwa baris pertama dan terakhir tidak kosong (dan tidak ada \x02, \x03atau \x04dalam input).

don_crissti
sumber
1

Anda BISA melakukannya dengan satu instance dari sed; tidak perlu pipa. Karena sedhanya membuat satu melewati dokumen dan karena bagian dari file yang diperlukan sebagai awal output adalah di akhir file, itu akan memerlukan memegang seluruh file dalam memori di dalam sed(di ruang penahanan) —jadi mungkin tidak skala dengan baik. Tapi itu menjawab pertanyaan dengan tepat:

:getpara
   ${
      s/$/\
/
      G
      s/\n\n$//
      q
   }
   N
   /\n$/!bgetpara
G
h
$!d
s/\n\n$//
q

Jika tidak ada trailing newline, ini masih berfungsi dengan baik. Jika ada satu baris baru yang tertinggal, itu ditekan dalam output (yaitu tidak akan ada baris baru dalam output). Jika ada (misalnya) 5 baris baru di input, akan ada 4 baris baru di output.

Kesenjangan antar paragraf dipertahankan.

Spasi putih pada baris yang kosong TIDAK diperlakukan sebagai paragraf break, tapi itu fitur, bukan bug. :)

Anda juga dapat melakukan ini sebagai one-liner yang jauh lebih mudah dibaca:

sed ':k;${;s/\(\(\n\).*\)$/\1\2/;G;s/\n\n$//;q;};N;/\n$/!bk;G;h;$!d;s/\n\n$//;q' inputfile

Meskipun ini hanya berfungsi dengan GNU sed. (Catat penggunaan backreferences yang sulit untuk dilakukan s/$/\n/. Tanpa ini, itu tidak akan menjadi satu-liner literal karena akan mengandung garis miring terbalik-baru.)

Wildcard
sumber
jadi Anda menyeruput file itu, kan? sepertinya Anda meletakkan semuanya di ruang tunggu. dg G;h. Anda mungkin menyebutkan sesuatu tentang batasan input atau sejenisnya.
mikeserv
Saya tidak menguji one-liner karena saya bekerja dari Mac saya dan tidak memiliki GNU yang sedberguna, tetapi versi skrip pasti menjaga celah di antara paragraf. Saya baru saja mengujinya atas masukan Anda. Apakah Anda menguji versi skrip?
Wildcard
@ mikeserv: Jelas benar. (Akan memperbarui malam ini.)
Wildcard
0
gem install facets

ruby -r facets/string \
     -e 'puts $stdin.read.strip.shatter(/\n\n+/).reverse.join("")' < file

Ini harus menjaga jarak paragraf Anda (sementara lebih mudah dibaca daripada sed:)) Meskipun, alat untuk devnull untuk jawaban yang luar biasa.

Amadan
sumber