Rimozione di righe duplicate in vi?


123

Ho un file di testo che contiene un lungo elenco di voci (una su ogni riga). Alcuni di questi sono duplicati e vorrei sapere se è possibile (e se sì, come) rimuovere eventuali duplicati. Sono interessato a farlo dall'interno di vi / vim, se possibile.



4
Questo ha 1 anno; quello è di 10 mesi. Quindi, al contrario.
Sydius

Il consenso di @Sydius ora è dare la priorità al conteggio dei voti positivi (di cui ne hai anche di più): meta.stackexchange.com/questions/147643/… E quelli non sono duplicati, quello non menziona Vim :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Risposte:


269

Se sei d'accordo con l'ordinamento del tuo file, puoi usare:

:sort u

6
Questo è così bello. Grazie!
Shrayas

8
Se l'ordinamento non è accettabile, utilizzare :%!uniqper rimuovere semplicemente le voci duplicate senza ordinare il file.
criptico0

una volta usato il comando l'intero file cambia? come torni indietro? Ho già salvato il file per errore ... colpa mia
nilon


25

Prova questo:

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

Cerca qualsiasi riga immediatamente seguita da una o più copie di se stessa e la sostituisce con una singola copia.

Fai una copia del tuo file prima di provarlo. Non è stato testato.


1
@hop Grazie per averlo provato per me. Non avevo accesso a vim in quel momento.
Sean

2
questo evidenzia tutte le righe duplicate per me ma non cancella, mi manca un passaggio qui?
ak85

Sono abbastanza sicuro che questo evidenzierà anche una riga seguita da una riga che ha lo stesso "prefisso" ma è più lunga.
Hippietrail

3
L'unico problema con questo è che se hai più duplicati (3 o più delle stesse righe), devi eseguirlo molte volte fino a quando tutti i duplicati sono spariti poiché questo li rimuove solo un set di duplicati alla volta.
horta

2
Un altro svantaggio di questo: questo non funzionerà a meno che le linee duplicate non siano già una accanto all'altra. Ordinare per primo sarebbe un modo per assicurarsi che siano uno accanto all'altro. A quel punto, le altre risposte sono probabilmente migliori.
horta

23

Dalla riga di comando basta fare:

sort file | uniq > file.new

1
Questo è stato molto utile per me per un file enorme. Grazie!
Rafid

1
Non sono riuscito a far funzionare la risposta accettata, perché :sort uera appeso al mio file di grandi dimensioni. Questo ha funzionato molto rapidamente e perfettamente. Grazie!
Tgsmith61591

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

1
Sì, ho provato questa tecnica su un file da 2,3 GB ed è stato incredibilmente veloce.
DanM

@hippietrail Sei su PC Windows? Forse puoi usare cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtse vuoi preservare l'ordine (cioè, l'ordinamento non è accettabile). Per richiamarlo da vim, :!può essere utilizzato.


4
È adorabile! Non aver bisogno di smistare è esattamente quello che stavo cercando!
Cometsong

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

Funziona per me su Windows. Le righe devono essere ordinate prima però.


1
Questo cancellerà una riga che segue una riga che è il suo prefisso: aaaaseguito da aaaabbcancellerà aaaaerroneamente.
Hippietrail

5

Combinerei due delle risposte sopra:

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

1G
!Gsort
1G
!Guniq

Se ti interessava vedere quante righe duplicate sono state rimosse, usa control-G prima e dopo per controllare il numero di righe presenti nel tuo buffer.


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

3

Seleziona le linee in modalità linea visuale ( Shift+ v), quindi :!uniq. Questo catturerà solo i duplicati che vengono uno dopo l'altro.


1
Solo per notare che questo funzionerà solo su computer con il programma uniq installato cioè Linux, Mac, Freebsd ecc.
anteatersa

Questa sarà la migliore risposta a coloro che non hanno bisogno di smistamento. E se sei un utente di Windows, considera di provare Cygwin o MSYS.
fx-kirin

1

Per quanto riguarda il modo in cui Uniq può essere implementato in VimL, ​​cerca Uniq in un plugin che sto mantenendo . Vedrai vari modi per implementarlo che sono stati forniti nella mailing list di Vim.

Altrimenti, :sort uè davvero la strada da percorrere.


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

o

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

questa è la mia risposta per te, può rimuovere più linee duplicate e tenerne solo una non rimuoverla!


0

Lo userei !}uniq, ma funziona solo se non ci sono righe vuote.

Per ogni riga in un file di uso: :1,$!uniq.


0

Questa versione rimuove solo le righe ripetute che sono contigue. Voglio dire, elimina solo le righe ripetute consecutive. Utilizzando la mappa data, la funzione nota incasinare le righe vuote. Ma se si modifica il REGEX in modo che corrisponda all'inizio della riga ^, verranno rimosse anche le righe vuote duplicate.

" 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

Un metodo alternativo che non utilizza vi / vim (per file molto grandi), è dalla riga di comando di Linux utilizzare sort e uniq:

sort {file-name} | uniq -u

0

Questo ha funzionato per me sia per .csve.txt

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

Spiegazione: La prima parte del comando stampa righe univoche e la seconda parte, cioè dopo la freccia centrale, salva l'output della prima parte.

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

>

<newFileName>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.