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.

Sydius
źródło
1
Wygląda na duplikat stackoverflow.com/questions/746689/ ...
Nathan Fellman
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:

269

Jeśli nie masz nic przeciwko sortowaniu pliku, możesz użyć:

:sort u
Brian Carper
źródło
6
To jest takie piękne. Dzięki!
Shrayas
8
Jeśli sortowanie jest niedopuszczalne, użyj go, :%!uniqaby po prostu usunąć zduplikowane wpisy bez sortowania pliku.
cryptic0
gdy użyjesz polecenia, cały plik się zmieni? jak wracasz
Zapisałem
Po prostu użyj polecenia cofania Vima :u
adampasz
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.

Sean
źródło
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
Kevin
źródło
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ć.

Rovin Bhandari
źródło
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.

Bridgey
źródło
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.

Jon DellOro
źródło
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.

derobert
źródło
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.

Luc Hermitte
źródło
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ąć!

cn8341
źródło
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.

Chris Dodd
źródło
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>
SergioAraujo
źródło
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
william-1066
źródło
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>

Paweł
źródło