Bagaimana cara membalik urutan garis?


24

Bagaimana saya bisa membalik urutan baris sehingga baris pertama muncul di akhir dan baris terakhir muncul terlebih dahulu? (Bisa jadi semua baris dalam buffer, rentang alamat, atau pemilihan mode visual secara garis.)

Saya ingin berubah

rat
ox
tiger
⋮
dog
pig

ke

pig
dog
⋮
tiger
ox
rat

tanpa menggunakan perintah eksternal seperti tac.


Ada saran untuk tag yang lebih baik pada pertanyaan ini?
200_sukses

1
mungkin tag 'pure-vi' baru atau serupa? Saya telah melihat beberapa pertanyaan yang akan mendapat manfaat dari tag yang akan menunjukkan keinginan untuk tidak melibatkan alat eksternal. Haruskah saya bertanya tentang itu di Meta?
John O'M.

1
@Carpetsmoker (dan siapa pun yang tertarik mengikuti ini) pertanyaan tag sekarang ada di meta meta.vi.stackexchange.com/questions/1229/…
John O'M.

Jawaban:


29

Kekuatan global akan bekerja di sini:

:g/^/exe "normal ddggP"

Atau, lebih sederhana (terima kasih @tommcdo)

:g/^/move 0

Yang pertama akan cocok dengan setiap baris dan untuk setiap baris, hapus dan tempel ke bagian atas file. Saat bergerak melalui file, itu membalikkan teks.

Yang kedua sama cocok dengan setiap baris dan memindahkannya ke bagian atas file.

Catatan: Keduanya berfungsi pada seluruh file dan tidak akan berlaku dengan benar untuk membalikkan bagian dari baris. Lihat jawaban Ingo Karkat untuk solusi yang bekerja dalam kisaran.

Deskripsi:

gperintah global
/^/cocok dengan semua baris yang memiliki permulaan (yaitu semua baris)
exejalankan string berikut ini
"normallakukan perintah mode normal
ddhapus baris
ggpindah ke atas
Ptempel file di atas posisi saat ini

move 0 memindahkan baris saat ini ke bawah garis 0 (yang menempatkannya di posisi 1, atau baris pertama file)


6
Alih-alih :normalperintah, kita bisa menggunakan perintah Ex :move 0, yang memindahkan garis ke awal buffer.
tommcdo

1
Juga :executehanya diperlukan ketika perintah perlu dibangun secara dinamis, mis :execute 'normal' g:user_command.
tommcdo

@tommcdo poin bagus! Saya terbiasa menggunakan :executekarena saya sering berakhir menambahkan perintah Ex lain setelah yang ada nanti, dan lebih mudah bagi saya untuk memiliki di :exesana daripada harus kembali dan memasukkannya nanti. Sayangnya, kebiasaan itu bocor ke jawaban ini di mana itu tidak berlaku banyak.
John O'M.

1
Penjelasan lebih lanjut tentang penggunaan saya atas :execute: karena dibutuhkan sebuah string, ia memberikan penggambaran yang jelas untuk di mana perintah mode-normal berakhir, meskipun saya tidak membangun string, lebih mudah bagi saya untuk menemukan tanda kutip yang seimbang daripada mencari <esc>atau apa pun untuk menghentikan mode. Sekali lagi, ini adalah preferensi dan kebiasaan pribadi. :-)
John O'M.

3
Ini akan bekerja untuk rentang btw: :9,11g/^/move 8... Angka terakhir harus menjadi awal rentang minus 1 (diadaptasi dari jawaban Ingo).
Martin Tournoij

13

Baris satu ini (untuk Anda ~/.vimrc) mendefinisikan sebuah :Reverseperintah; Anda juga dapat menggunakan :globalbagian tersebut secara langsung, tetapi sintaksisnya :move(yang secara iteratif menggeser garis sebelum dimulainya rentang, dengan demikian membalikkannya) tidak mudah untuk dihafal:

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1

1
Sebagai FYI untuk pembaca, <line1>& <line2>diminta untuk membuat karya ini pada kisaran, yaitu: :7,9Reverse(mereka fitur command, bukan globalatau move). Yang lebih sederhana :command! -bar -range=% Reverse :global/^/m 0juga akan berfungsi, tetapi hanya untuk seluruh penyangga ...
Martin Tournoij

6

Vim murni:

:g/^/m0

Penjelasan:

Menurut :help multi-repeat, :gdan sepupunya :vbekerja dengan dua cara.

Pass pertama :gmenandai setiap baris yang cocok {pattern}, sedangkan pass kedua (tampaknya dilakukan mulai dari awal file dan melanjutkan ke akhir) melakukan [cmd]. Penggunaan di atas :gmemanfaatkan urutan jalur diproses (yang mungkin baik-baik saja, meskipun mungkin tidak dijamin secara teknis).

Ini bekerja dengan terlebih dahulu menandai setiap baris, kemudian memindahkan baris yang ditandai pertama ke atas file, kemudian memindahkan yang kedua ke atas file (di atas garis yang dipindahkan sebelumnya), kemudian baris yang ditandai ketiga (lagi di atas yang sebelumnya dipindahkan baris), dan seterusnya hingga baris terakhir dalam file dipindahkan ke atas, secara efektif membalikkan file.

Perhatikan bahwa jika :gbaris yang diproses dalam urutan apa pun selain dari atas ke bawah, perintah ini tidak akan berfungsi.

Sumber: Membalik semua garis dan Kekuatan g pada vim wikia.

Beberapa contoh menggunakan perintah eksternal:

  • tac(bagian dari GNU coreutils - catterbalik):

    :%!tac                                                                                                                                                                                                                                                              
    
  • tail pada BSD / OSX (tidak kompatibel dengan POSIX):

    :%!tail -r
    

    -r Opsi -r menyebabkan input ditampilkan dalam urutan terbalik, per baris.

    Periksa: man taruntuk lebih jelasnya.

Untuk lebih banyak ide, lihat:


2
Bukankah :g/^/m0sama dengan :g/^/move 0, yang merupakan jawaban John?
muru

@uru saya rasa begitu, tapi yang ini lebih pendek (menurut vim wikia) dan saya telah menambahkan penjelasan berbeda dengan beberapa contoh tambahan menggunakan baris perintah.
kenorb

Ya, saya tidak memilih karena perintah lain (saya datang untuk memposting tacjuga). Tetapi saya menduga downvote itu karena jawaban yang diulang.
muru

Saya sadar bahwa tacdisebutkan oleh OP, tetapi semua pertanyaan serupa lainnya akan merupakan duplikat dari ini, jadi ada baiknya untuk menyebutkannya lagi. John mengambil cmd ini dari komentar @tommcdo, saya awalnya mengambilnya dari DerMike , tapi saya pikir dia mengambilnya hanya dari wikia, jadi saya memberikan kredit kepada vim wikia, jadi itu tidak sepenuhnya duplikat karena penjelasannya sangat berbeda.
kenorb

Ini menambah nilai lebih, karena versi yang jauh lebih pendek dengan penjelasan yang tepat dan saya juga mengkredit sumber yang tepat. Menggunakan perintah shell sangat sederhana dan nyaman. Jika orang tidak setuju, mereka bisa memilih, bukan masalah besar.
kenorb

6

Dalam semangat VIML fungsional:

:call setline(1, reverse(getline(1, line('$'))))
  • getline(1, line('$'))mengembalikan daftar semua baris dalam buffer. '$'adalah argumen khusus line()yang menunjukkan baris terakhir dalam buffer.
  • reverse(...)membalikkan daftar input, di tempat. Seseorang harus menggunakan reverse(copy(...))jika daftar input tidak boleh dimodifikasi.
  • setline(1, ...)mengganti baris yang ditentukan dengan argumen kedua. Ketika argumen kedua adalah daftar, jumlah baris yang sama dengan panjang daftar diganti dengan konten daftar.

Jika suka, Anda juga dapat menentukan perintah yang mengambil rentang ( %buffer keseluruhan default )

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))

1
Saya suka jawaban ini. Itu juga tidak menyoroti hal-hal (jika hlsearchdiaktifkan) seperti :g/perintah dari jawaban lain ... Kinerja mungkin lebih buruk, sih ? Karena getline(1, line('$'))mendapat seluruh buffer dalam memori. reverse()tampaknya di tempat, sehingga harus mengambil memori sangat sedikit seperti ...
Martin Tournoij

3

Per Dokumentasi Vim usr_12.txt - Trik Pintar

12.4 Urutan garis terbalik

The :globalperintah dapat dikombinasikan dengan :moveperintah untuk memindahkan semua baris sebelum baris pertama, sehingga file terbalik. Perintahnya adalah:

:global/^/m 0

Disingkat:

:g/^/m 0

The ^ekspresi reguler sesuai dengan awal baris (bahkan jika baris kosong). The :moveperintah bergerak garis yang cocok untuk setelah baris ke nol mitos, sehingga garis yang cocok saat ini menjadi baris pertama dari file. Karena :globalperintah tidak bingung dengan penomoran baris yang berubah, :globalhasilkan untuk mencocokkan semua baris file yang tersisa dan menempatkan masing-masing sebagai yang pertama.

Ini juga berfungsi pada berbagai garis. Langkah pertama ke atas baris pertama dan tandai dengan mt. Kemudian pindahkan kursor ke baris terakhir dalam rentang dan ketik:

:'t+1,.g/^/m 't

1

Menggunakan angka relatif. Paragraf dimulai pada baris 13 dan mengirim lebih banyak 4 baris

 :13,13+4g/^/m12
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.