Menghapus baris duplikat di vi?


123

Saya memiliki file teks yang berisi daftar panjang entri (satu di setiap baris). Beberapa di antaranya adalah duplikat, dan saya ingin tahu apakah mungkin (dan jika demikian, bagaimana) menghapus duplikat apa pun. Saya tertarik melakukan ini dari dalam vi / vim, jika memungkinkan.



4
Yang ini berumur 1 tahun; yang satu itu 10 bulan. Jadi, sebaliknya.
Sydius

Konsensus @Sydius sekarang adalah memprioritaskan jumlah suara positif (yang juga Anda miliki lebih banyak): meta.stackexchange.com/questions/147643/… Dan itu bukan duplikat, yang tidak menyebutkan Vim :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Jawaban:


269

Jika Anda setuju dengan penyortiran file Anda, Anda dapat menggunakan:

:sort u

6
Ini sangat cantik. Terima kasih!
Shrayas

8
Jika pengurutan tidak dapat diterima, gunakan :%!uniquntuk menghapus entri duplikat tanpa mengurutkan file.
cryptic0

setelah Anda menggunakan perintah, seluruh file berubah? bagaimana kamu kembali? Saya telah menyimpan file karena kesalahan ... salah saya
nilon

Cukup gunakan perintah urungkan Vim :u
adampasz

25

Coba ini:

:%s/^\(.*\)\(\n\1\)\+$/\1/

Ini mencari baris apa pun segera diikuti oleh satu atau lebih salinan dari dirinya sendiri, dan menggantinya dengan satu salinan.

Buat salinan file Anda sebelum Anda mencobanya. Ini belum teruji.


1
@hop Terima kasih telah mengujinya untuk saya. Saya tidak memiliki akses ke vim saat itu.
Sean

2
ini menyoroti semua baris duplikat untuk saya tetapi tidak menghapus, apakah saya melewatkan satu langkah di sini?
ak85

Saya cukup yakin ini juga akan menyoroti sebuah baris yang diikuti oleh sebuah baris yang memiliki "awalan" yang sama tetapi lebih panjang.
hippietrail

3
Satu-satunya masalah dengan ini adalah jika Anda memiliki beberapa duplikat (3 atau lebih dari baris yang sama), Anda harus menjalankan ini berkali-kali sampai semua dup hilang karena ini hanya menghapusnya satu set dup pada satu waktu.
horta

2
Kelemahan lain dari ini: ini tidak akan berfungsi kecuali garis duplikat Anda sudah bersebelahan. Menyortir lebih dulu akan menjadi salah satu cara untuk memastikan mereka bersebelahan. Pada titik itu, jawaban lain mungkin lebih baik.
horta

23

Dari baris perintah lakukan saja:

sort file | uniq > file.new

1
Ini sangat berguna bagi saya untuk file besar. Terima kasih!
Rafid

1
Tidak bisa mendapatkan jawaban yang diterima untuk bekerja, karena :sort utergantung di file besar saya. Ini bekerja dengan sangat cepat dan sempurna. Terima kasih!
Tgsmith61591

1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail

1
Ya - Saya mencoba teknik ini pada file 2,3 GB, dan ternyata sangat cepat.
DanM

@hippietrail Anda menggunakan Windows PC? Mungkin Anda bisa menggunakan cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtjika Anda ingin mempertahankan urutan (yaitu, penyortiran tidak dapat diterima). Untuk memanggilnya dari vim, :!bisa digunakan.


4
Ini bagus! Tidak perlu menyortir persis seperti yang saya cari!
Cometsong

6
g/^\(.*\)$\n\1/d

Bekerja untuk saya di Windows. Garis harus diurutkan terlebih dahulu.


1
Ini akan menghapus sebuah baris yang mengikuti sebuah baris yang merupakan awalannya: aaaadiikuti oleh aaaabbakan menghapus secara aaaakeliru.
hippietrail

5

Saya akan menggabungkan dua jawaban di atas:

go to head of file
sort the whole file
remove duplicate entries with uniq

1G
!Gsort
1G
!Guniq

Jika Anda tertarik untuk melihat berapa banyak baris duplikat yang dihapus, gunakan control-G sebelum dan sesudah untuk memeriksa jumlah baris yang ada di buffer Anda.


1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail

3

Pilih garis dalam mode garis visual ( Shift+ v), lalu :!uniq. Itu hanya akan menangkap duplikat yang datang satu demi satu.


1
Hanya untuk dicatat ini hanya akan bekerja pada komputer dengan program uniq diinstal yaitu Linux, Mac, Freebsd dll
anteatersa

Ini akan menjadi jawaban terbaik bagi mereka yang tidak perlu menyortir. Dan jika Anda pengguna windows, pertimbangkan untuk mencoba Cygwin atau MSYS.
fx-kirin

1

Mengenai bagaimana Uniq dapat diimplementasikan di VimL, ​​cari Uniq di plugin yang saya kelola . Anda akan melihat berbagai cara untuk menerapkannya yang diberikan di milis Vim.

Jika tidak, :sort umemang cara untuk pergi.


0
:%s/^\(.*\)\(\n\1\)\+$/\1/gec

atau

:%s/^\(.*\)\(\n\1\)\+$/\1/ge

ini jawaban saya untuk Anda, ini dapat menghapus beberapa baris duplikat dan hanya menyimpan satu tidak menghapus!


0

Saya akan menggunakan !}uniq, tetapi itu hanya berfungsi jika tidak ada baris kosong.

Untuk setiap baris dalam sebuah file digunakan: :1,$!uniq.


0

Versi ini hanya menghapus garis berulang yang bersinggungan. Maksud saya, hanya menghapus baris berulang yang berurutan. Menggunakan peta yang diberikan, fungsinya tidak mengacaukan garis kosong. Tetapi jika mengubah REGEX agar sesuai dengan awal baris ^itu juga akan menghapus duplikat baris kosong.

" function to delete duplicate lines
function! DelDuplicatedLines()
    while getline(".") == getline(line(".") - 1)
        exec 'norm! ddk'
    endwhile
    while getline(".") == getline(line(".") + 1)
        exec 'norm! dd'
    endwhile
endfunction
nnoremap <Leader>d :g/./call DelDuplicatedLines()<CR>

0

Metode alternatif yang tidak menggunakan vi / vim (untuk file yang sangat besar), adalah dari baris perintah Linux gunakan sort dan uniq:

sort {file-name} | uniq -u

0

Ini berhasil bagi saya untuk keduanya .csvdan.txt

awk '!seen[$0]++' <filename> > <newFileName>

Penjelasan: Bagian pertama dari perintah mencetak baris unik dan bagian kedua yaitu setelah panah tengah adalah untuk menyimpan keluaran dari bagian pertama.

awk '!seen[$0]++' <filename>

>

<newFileName>

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.