Usunięcie zduplikowanych wierszy w vi?


123

Mam plik tekstowy zawierający długą listę wpisów (po jednym w każdym wierszu). Niektóre z nich są duplikatami i chciałbym wiedzieć, czy można (a jeśli tak, w jaki sposób) usunąć jakiekolwiek duplikaty. Jeśli to możliwe, jestem zainteresowany zrobieniem tego z poziomu vi / vim.



4
Ten ma 1 rok; ten jest 10 miesięcy. Więc na odwrót.
Sydius

Konsensus @Sydius polega teraz na nadaniu priorytetu liczbie głosów w górę (której też masz więcej): meta.stackexchange.com/questions/147643/… A to nie są duplikaty, że nie wspomina się o Vimie :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Odpowiedzi:



25

Spróbuj tego:

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

Wyszukuje dowolny wiersz, po którym bezpośrednio następuje jedna lub więcej kopii samego siebie i zastępuje go pojedynczą kopią.

Zanim jednak spróbujesz, zrób kopię swojego pliku. To nie zostało przetestowane.


1
@hop Dzięki za przetestowanie go dla mnie. Nie miałem wtedy dostępu do vima.
Sean,

2
podświetla to dla mnie wszystkie zduplikowane linie, ale nie usuwa, czy brakuje mi kroku tutaj?
ak85

Jestem prawie pewien, że podświetli to również linię, po której nastąpi linia, która ma ten sam „prefiks”, ale jest dłuższa.
hippietrail

3
Jedynym problemem jest to, że jeśli masz wiele duplikatów (3 lub więcej takich samych linii), musisz uruchomić to wiele razy, aż wszystkie duplikaty znikną, ponieważ usuwa to tylko jeden zestaw dup na raz.
horta

2
Kolejna wada: to nie zadziała, chyba że zduplikowane linie są już obok siebie. Sortowanie najpierw byłoby jednym ze sposobów upewnienia się, że znajdują się obok siebie. W tym momencie inne odpowiedzi są prawdopodobnie lepsze.
horta

23

Z linii poleceń po prostu wykonaj:

sort file | uniq > file.new

1
To było dla mnie bardzo przydatne w przypadku dużego pliku. Dzięki!
Rafid

1
Nie udało się uzyskać zaakceptowanej odpowiedzi, ponieważ :sort uwisiało na moim dużym pliku. Działało to bardzo szybko i doskonale. Dziękuję Ci!
Tgsmith61591

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

1
Tak - wypróbowałem tę technikę na pliku 2,3 ​​GB i było to szokująco szybkie.
DanM

@hippietrail Jesteś na komputerze z systemem Windows? Może możesz użyć cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtjeśli chcesz zachować kolejność (np. sortowanie jest niedopuszczalne). Aby wywołać go z vima, :!można użyć.


4
To jest urocze! Brak konieczności sortowania jest dokładnie tym , czego szukałem!
Cometsong

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

U mnie działa w systemie Windows. Jednak linie muszą być najpierw posortowane.


1
Spowoduje to usunięcie wiersza następującego po wierszu, który jest jego przedrostkiem: aaaapo którym aaaabbnastąpi, spowoduje aaaabłędne usunięcie .
hippietrail

5

Połączyłbym dwie z powyższych odpowiedzi:

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

1G
!Gsort
1G
!Guniq

Jeśli chciałbyś zobaczyć, ile zduplikowanych linii zostało usuniętych, użyj control-G przed i po, aby sprawdzić liczbę linii obecnych w twoim buforze.


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

3

Następnie zaznacz linie w trybie linii wizualnych ( Shift+ v) :!uniq. To wyłapie tylko duplikaty, które pojawiają się jeden po drugim.


1
Pamiętaj, że będzie to działać tylko na komputerach z zainstalowanym programem uniq, tj. Linux, Mac, Freebsd itp.
anteatersa

To będzie najlepsza odpowiedź dla tych, którzy nie potrzebują sortowania. A jeśli jesteś użytkownikiem systemu Windows, rozważ wypróbowanie Cygwin lub MSYS.
fx-kirin

1

Jeśli chodzi o sposób implementacji Uniqa w VimL, ​​wyszukaj Uniq we wtyczce, którą utrzymuję . Zobaczysz różne sposoby implementacji, które zostały podane na liście mailingowej Vima.

W przeciwnym razie :sort ujest to droga do zrobienia.


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

lub

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

to jest moja odpowiedź dla ciebie, może usunąć wiele zduplikowanych linii i zachować tylko jedną, której nie można usunąć!


0

Użyłbym !}uniq, ale to działa tylko wtedy, gdy nie ma pustych linii.

Dla każdego wiersza w użyciu pliku: :1,$!uniq.


0

Ta wersja usuwa tylko powtarzające się linie, które są ciągłe. Mam na myśli, że usuwa tylko kolejne, powtarzające się wiersze. Używając podanej mapy, funkcja zwraca uwagę na puste linie. Ale jeśli zmienisz REGEX, aby pasował do początku wiersza ^, usunie to również zduplikowane puste wiersze.

" 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

Alternatywną metodą, która nie używa vi / vim (dla bardzo dużych plików), jest użycie sort i uniq z wiersza poleceń Linuksa:

sort {file-name} | uniq -u

0

To działało dla mnie zarówno w przypadku, jak .csvi.txt

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

Objaśnienie: Pierwsza część polecenia drukuje unikalne wiersze, a druga część, tj. Po środkowej strzałce, ma na celu zapisanie wyniku pierwszej części.

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

>

<newFileName>

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.