Видалення повторюваних рядків у vi?


123

У мене є текстовий файл, який містить довгий список записів (по одному у кожному рядку). Деякі з них є дублікатами, і я хотів би знати, чи можна (і якщо так, як) видалити будь-які дублікати. Мені цікаво це робити, якщо можливо, в межах vi / vim.


1
Виглядає як дублікат stackoverflow.com/questions/746689 / ...
Натан Fellman

4
Цьому 1 рік; що один 10 місяців. Отже, навпаки.
Сидіус

Консенсус @Sydius зараз полягає в тому, щоб визначити пріоритетну кількість підрахунків (яких у вас також є більше): meta.stackexchange.com/questions/147643/… І це не дублікати, про які Вим не згадує :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Відповіді:


269

Якщо ви все в порядку зі сортуванням вашого файлу, ви можете використовувати:

:sort u

6
Це так красиво. Дякую!
Шрайас

8
Якщо сортування неприйнятне, використовуйте :%!uniqдля простого видалення повторюваних записів, не сортуючи файл.
cryptic0

як тільки ви використовуєте команду, весь файл змінюється? як ти повертаєшся назад? Я вже помилково
зберег

Просто використовуйте команду скасування Vim :u
adampasz

25

Спробуйте це:

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

Він шукає будь-який рядок, за яким відразу слідує одна чи кілька копій, і замінює його однією копією.

Зробіть копію свого файлу, хоча перш ніж спробувати. Це неперевірено.


1
@hop Дякую за тестування. У мене тоді не було доступу до vim.
Шон

2
ця підсвітка всіх повторюваних рядків для мене, але не видаляє, я пропускаю крок тут?
ak85

Я впевнений, що це також підкреслить рядок, за яким слідує рядок, який має той самий "префікс", але довший.
hippietrail

3
Єдине питання з цим полягає в тому, що якщо у вас є кілька дублікатів (3 і більше однакових рядків), вам доведеться запускати це багато разів, поки не зникнуть усі дупи, оскільки це видаляє їх лише один набір дупів за один раз.
хорта

2
Ще один недолік цього: це не працюватиме, якщо ваші повторювані рядки вже не стоять поруч. Сортування спочатку було б одним із способів гарантувати, що вони знаходяться поруч. На той момент інші відповіді, мабуть, кращі.
хорта

23

З командного рядка просто виконайте:

sort file | uniq > file.new

1
Це було дуже зручно для мене для величезного файлу. Дякую!
Рафід

1
Не вдалося отримати прийняту відповідь на роботу, оскільки це :sort uбуло на моєму великому файлі. Це спрацювало дуже швидко та ідеально. Дякую!
Tgsmith61591

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

1
Так - я спробував цю техніку на 2,3 ГБ файлі, і це було приголомшливо швидко.
DanM

@hippietrail Ви знаходитесь на комп'ютері з Windows? Можливо, ви можете використовувати cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtякщо ви хочете зберегти замовлення (тобто сортування неприйнятне). Для того, щоб викликати його від vim, :!можна використовувати.


4
Це прекрасно! Не потрібно сортувати - саме те , що я шукав!
Cometsong

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

Для мене працює у Windows. Лінії потрібно спочатку сортувати.


1
Це видалить рядок за рядком, який є його префіксом: aaaaпісля цього aaaabbбуде видалено aaaaпомилково.
hippietrail

5

Я б поєднав дві відповіді вище:

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

1G
!Gsort
1G
!Guniq

Якщо вам було цікаво побачити, скільки видалених повторних рядків, використовуйте control-G до і після, щоб перевірити кількість рядків у вашому буфері.


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

3

Виберіть лінії у візуально-лінійному режимі ( Shift+ v), потім :!uniq. Це будуть лише ложі дублікатів, які приходять один за одним.


1
Зауважимо, що це працюватиме лише на комп'ютерах із встановленою програмою uniq, тобто Linux, Mac, Freebsd тощо
anteatersa

Це буде найкращою відповіддю для тих, хто не потребує сортування. А якщо ви користувач Windows, спробуйте Cygwin або MSYS.
fx-kirin


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

або

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

це моя відповідь для вас, вона може видалити декілька повторюваних рядків і зберегти лише один!


0

Я б використав !}uniq, але це працює лише за відсутності порожніх рядків.

Для кожного рядка у файлі використовуйте: :1,$!uniq.


0

Ця версія видаляє лише повторні рядки, які є суміжними. Я маю на увазі, видаляє лише послідовні повторні рядки. Використовуючи дану карту, функція помічає псування з порожніми рядками. Але якщо змінити REGEX на збіг початку рядка, ^він також видалить повторювані порожні рядки.

" 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

Альтернативний метод, який не використовує vi / vim (для дуже великих файлів), з командного рядка Linux використовує sort і uniq:

sort {file-name} | uniq -u

0

Це працювало на мене і для, .csvі для.txt

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

Пояснення: Перша частина команди друкує унікальні рядки, а друга частина, тобто після середньої стрілки, зберігає вихід першої частини.

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

>

<newFileName>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.