Saya pikir perintah berikut harus bekerja:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Penjelasan:
Kami menggunakan perintah substitusi pada seluruh file untuk berubah pattern
menjadi string
:
:%s/pattern/string/
Berikut pattern
adalah ^\(.*\)\(\n\1\)\+$
dan string
adalah \1
.
pattern
dapat dipecah seperti ini:
^\(subpattern1\)\(subpattern2\)\+$
^
dan $
masing-masing cocok dengan awal garis dan akhir garis.
\(
dan \)
digunakan untuk melampirkan subpattern1
sehingga kita dapat merujuknya nanti dengan nomor khusus \1
.
Mereka juga digunakan untuk melampirkan subpattern2
sehingga kita dapat mengulanginya 1 atau lebih kali dengan kuantifier \+
.
subpattern1
adalah .*
.
metacharacter yang cocok dengan karakter apa pun kecuali baris baru dan *
merupakan penjumlah yang cocok dengan karakter terakhir 0, 1 atau lebih kali.
Jadi .*
cocok dengan teks apa pun yang tidak mengandung baris baru.
subpattern2
adalah \n\1
\n
cocok dengan baris baru dan \1
sesuai dengan teks yang sama yang disesuaikan dalam pertama \(
, \)
yang di sini adalah subpattern1
.
Jadi pattern
dapat dibaca seperti ini:
awal baris ( ^
) diikuti oleh teks yang tidak mengandung baris baru ( .*
) diikuti oleh baris baru ( \n
) kemudian teks yang sama ( \1
), dua baris terakhir diulang satu atau lebih kali ( \+
), dan akhirnya sebuah akhir baris ( $
) .
Di mana pun pattern
dicocokkan (blok dari garis yang identik), perintah substitusi menggantikannya dengan string
yang di sini adalah \1
(baris pertama dari blok).
Jika Anda ingin melihat blok garis mana yang akan terpengaruh tanpa mengubah apa pun di file Anda, Anda bisa mengaktifkan hlsearch
opsi dan menambahkan n
flag substitusi di akhir perintah:
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Untuk kontrol yang lebih terperinci, Anda juga dapat meminta konfirmasi sebelum mengubah setiap blok garis dengan menambahkan c
bendera pengganti sebagai gantinya:
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Untuk informasi lebih lanjut tentang perintah substitusi baca :help :s
,
untuk bendera substitusi :help s_flags
,
untuk berbagai metachar karakter dan quantifier dibaca :help pattern-atoms
,
dan untuk ekspresi reguler dalam vim baca ini .
Sunting: Wildcard memperbaiki masalah dalam perintah dengan menambahkan a $
di akhir pattern
.
BloodGain juga memiliki versi yang lebih pendek dan lebih mudah dibaca dari perintah yang sama.
$
di dalamnya, meskipun. Kalau tidak, ia akan melakukan hal-hal yang tidak terduga dengan garis yang dimulai dengan teks yang identik dengan baris sebelumnya, tetapi memiliki beberapa karakter tambahan lainnya. Perhatikan juga bahwa perintah dasar yang Anda berikan secara fungsional setara dengan jawaban saya:%!uniq
, tetapi flag highlight dan konfirmasi bagus.\n
cocok dengan ujung garis dan harus mencegah ini tetapi tidak. Saya mencoba menambahkan$
setelah setelah itu.*
tidak berhasil. Saya akan mencoba dan memperbaikinya, tetapi jika saya tidak bisa, mungkin saya akan menghapus jawaban saya atau menambahkan peringatan di akhir. Terima kasih telah menunjukkan masalah ini.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
cocok dengan akhir string , bukan akhir baris. Ini secara teknis tidak benar — tetapi ketika Anda menempatkan karakter setelah itu selain beberapa pengecualian, itu cocok dengan literal dan$
bukan sesuatu yang istimewa. Jadi menggunakan\n
lebih baik untuk pertandingan multi-line. (Lihat:help /$
)\n
dapat digunakan di mana saja di dalam regex sedangkan$
mungkin hanya boleh digunakan di akhir. Hanya untuk membuat perbedaan di antara keduanya, saya telah mengedit jawaban dengan menulis yang\n
cocok dengan baris baru (yang secara naluriah membuat Anda berpikir bahwa masih ada beberapa teks setelahnya) sedangkan$
cocok dengan akhir baris (yang membuat Anda berpikir bahwa tidak ada apa-apa) kiri).Coba yang berikut ini:
Seperti halnya jawaban saginaw , ini menggunakan perintah Vim's: pengganti. Namun, memanfaatkan beberapa fitur tambahan untuk meningkatkan keterbacaan:
\v
berarti "sangat ajaib," atau semua karakter kecuali alfanumerik ( A-z0-9 ) dan garis bawah ( _ ) memiliki arti khusus.Arti komponen adalah:
sumber
\n
dan$
.\n
menambahkan sesuatu ke dalam pola: karakter baris baru yang memberitahu vim bahwa teks berikut ada pada baris baru. Sedangkan$
tidak menambahkan apa pun ke pola, itu hanya melarang kecocokan yang akan dibuat jika karakter berikutnya di luar pola bukan garis baru. Setidaknya, itulah yang saya mengerti dengan membaca jawaban Anda dan:help zero-width
.^
, itu tidak menambahkan apa pun ke pola, itu hanya mencegah kecocokan yang akan dilakukan jika karakter sebelumnya di luar pola bukan garis baru ...+
berarti "ulangi ekspresi sebelumnya (karakter atau grup) 1 atau lebih kali," tetapi tidak cocok dengan apa pun itu sendiri. The^
berarti "tidak dapat memulai di tengah-tengah string" dan$
berarti "tidak berakhir di tengah string." Perhatikan saya tidak mengatakan "baris," tetapi "string" di sana. Vim memperlakukan setiap baris sebagai string secara default - dan di situlah\n
masuk. Ia memberitahu Vim untuk menggunakan baris baru untuk mencoba membuat kecocokan ini.Jika Anda ingin menghapus SEMUA garis identik yang berdekatan, tidak hanya
Hold
, Anda dapat melakukannya dengan sangat mudah dengan filter eksternal dari dalamvim
::%!uniq
(dalam lingkungan Unix).Jika Anda ingin melakukannya secara langsung
vim
, sebenarnya sangat rumit. Saya pikir ada cara, tetapi untuk kasus umum sangat sulit untuk membuatnya berfungsi 100% dan saya belum menyelesaikan semua bug.Namun, untuk kasus khusus ini, karena Anda dapat melihat secara visual bahwa baris berikutnya yang bukan duplikat tidak dimulai dengan karakter yang sama, Anda dapat menggunakan:
The
+
berarti baris setelah baris saat ini. . merujuk ke baris saat ini. The/^[^H]/-
berarti garis sebelum (-
) baris berikutnya yang tidak dimulai dengan H.Kemudian d dihapus.
sumber
uniq
(baik dari dalam vim atau menggunakan shell) adalah bagaimana saya akan menyelesaikan ini. Untuk satu hal, saya cukup yakinuniq
akan menangani garis yang kosong / semua ruang sebagai setara (tidak mengujinya), tetapi itu akan jauh lebih sulit untuk ditangkap dengan regex. Itu juga berarti tidak "menciptakan kembali roda" ketika saya sedang berusaha menyelesaikan pekerjaan.Jawaban berbasis Vim:
= Ganti setiap baris diikuti dengan sendiri setidaknya sekali , dengan baris yang sama.
sumber
Satu lagi, dengan asumsi Vim 7.4.218 atau lebih baru:
Namun ini tidak selalu lebih baik daripada solusi lainnya.
sumber
Berikut ini adalah solusi berdasarkan vim (golf) lama (2003) oleh Preben Gulberg dan Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(setara dengan:%Uniq
),:1,Uniq
(dari awal buffer ke baris saat ini),:Uniq<cr>
(diperluas dengan vim ke:'<,'>Uniq
):h range
)Ini kodenya:
Catatan: upaya pertama mereka adalah:
sumber