Loại bỏ các hàng trùng lặp trong vi?


123

Tôi có một tệp văn bản chứa một danh sách dài các mục nhập (một mục trên mỗi dòng). Một số trong số này là các bản sao và tôi muốn biết liệu có thể (và nếu có, làm thế nào) để loại bỏ bất kỳ bản sao nào. Tôi muốn làm điều này từ bên trong vi / vim, nếu có thể.


1
Có vẻ như một bản sao của stackoverflow.com/questions/746689/…
Nathan Fellman

4
Con này 1 tuổi; cái đó là 10 tháng. Vì vậy, ngược lại.
Sydius

@Sydius đồng thuận bây giờ là ưu tiên số phiếu ủng hộ (mà bạn cũng có nhiều hơn): meta.stackexchange.com/questions/147643/… Và đó không phải là bản sao, cái đó không đề cập đến Vim :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Câu trả lời:


269

Nếu bạn đồng ý với việc sắp xếp tệp của mình, bạn có thể sử dụng:

:sort u

6
Thật là đẹp. Cảm ơn!
Shrayas

8
Nếu việc sắp xếp là không thể chấp nhận được, hãy sử dụng :%!uniqđể loại bỏ các mục nhập trùng lặp mà không cần sắp xếp tệp.
cryptic0

khi bạn sử dụng lệnh, toàn bộ tệp sẽ thay đổi? làm thế nào để bạn quay trở lại? Tôi đã lưu tệp do nhầm lẫn ... lỗi của tôi
nilon

Chỉ cần sử dụng lệnh hoàn tác của Vim :u
adampasz

25

Thử cái này:

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

Nó tìm kiếm bất kỳ dòng nào ngay sau đó là một hoặc nhiều bản sao của chính nó và thay thế nó bằng một bản sao duy nhất.

Tạo một bản sao của tệp của bạn trước khi bạn thử nó. Nó chưa được kiểm tra.


1
@hop Cảm ơn bạn đã test giúp mình. Tôi không có quyền truy cập vào vim vào thời điểm đó.
Sean

2
điều này làm nổi bật tất cả các dòng trùng lặp cho tôi nhưng không xóa, tôi có thiếu một bước ở đây không?
ak85 14/09/12

Tôi khá chắc rằng điều này cũng sẽ đánh dấu một dòng theo sau là một dòng có cùng "tiền tố" nhưng dài hơn.
hippietrail,

3
Vấn đề duy nhất với điều này là nếu bạn có nhiều bản sao (3 hoặc nhiều hơn các dòng giống nhau), bạn phải chạy điều này nhiều lần cho đến khi hết tất cả các bản sao vì thao tác này chỉ loại bỏ chúng một tập hợp các bản sao một lần.
horta

2
Một nhược điểm khác của điều này: điều này sẽ không hoạt động trừ khi các dòng trùng lặp của bạn đã nằm cạnh nhau. Sắp xếp trước sẽ là một cách để đảm bảo chúng ở cạnh nhau. Tại thời điểm đó, các câu trả lời khác có lẽ tốt hơn.
horta

23

Từ dòng lệnh chỉ cần làm:

sort file | uniq > file.new

1
Điều này rất hữu ích cho tôi đối với một tệp lớn. Cảm ơn!
Rafid

1
Không thể làm cho câu trả lời được chấp nhận hoạt động, như :sort uđã bị treo trên tệp lớn của tôi. Điều này làm việc rất nhanh chóng và hoàn hảo. Cảm ơn bạn!
Tgsmith61591

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

1
Có - Tôi đã thử kỹ thuật này trên tệp 2,3 GB và nó nhanh chóng đến kinh ngạc.
DanM

@hippietrail Bạn đang sử dụng Windows PC? Có lẽ bạn có thể sử dụng cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtnếu bạn muốn giữ nguyên thứ tự (tức là không thể chấp nhận sắp xếp). Để gọi nó từ vim, :!có thể được sử dụng.


4
Cái này thật đáng yêu! Không cần phải sắp xếp chính xác là những gì tôi đang tìm kiếm!
Cometsong

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

Hoạt động cho tôi trên Windows. Mặc dù vậy, các dòng phải được sắp xếp trước.


1
Thao tác này sẽ xóa một dòng theo sau một dòng là tiền tố của nó: aaaatiếp theo là aaaabbsẽ xóa aaaanhầm.
hippietrail

5

Tôi sẽ kết hợp hai trong số các câu trả lời ở trên:

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

1G
!Gsort
1G
!Guniq

Nếu bạn muốn xem có bao nhiêu dòng trùng lặp đã bị xóa, hãy sử dụng control-G trước và sau để kiểm tra số dòng có trong bộ đệm của bạn.


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

3

Sau đó, chọn các đường ở chế độ đường trực quan ( Shift+ v) :!uniq. Điều đó sẽ chỉ bắt được các bản sao lần lượt xuất hiện.


1
Chỉ cần lưu ý điều này sẽ chỉ hoạt động trên các máy tính có cài đặt chương trình uniq, tức là Linux, Mac, Freebsd, v.v.
anteatersa

Đây sẽ là câu trả lời tốt nhất cho những ai không cần phân loại. Và nếu bạn là người dùng windows, hãy cân nhắc dùng thử Cygwin hoặc MSYS.
fx-kirin

1

Về cách Uniq có thể được triển khai trong VimL, ​​hãy tìm kiếm Uniq trong một plugin mà tôi đang duy trì . Bạn sẽ thấy nhiều cách khác nhau để thực hiện nó đã được cung cấp trong danh sách gửi thư Vim.

Nếu không, :sort uthực sự là con đường để đi.


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

hoặc là

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

đây là câu trả lời của tôi dành cho bạn, nó có thể loại bỏ nhiều dòng trùng lặp và chỉ giữ một dòng không bị xóa!


0

Tôi sẽ sử dụng !}uniq, nhưng điều đó chỉ hoạt động nếu không có dòng trống.

Đối với mỗi dòng trong một tập tin sử dụng: :1,$!uniq.


0

Phiên bản này chỉ loại bỏ các dòng lặp đi lặp lại không liên quan. Ý tôi là, chỉ xóa các dòng lặp lại liên tiếp. Sử dụng bản đồ đã cho, chức năng ghi chú sẽ lộn xộn với các dòng trống. Nhưng nếu thay đổi REGEX để phù hợp với đầu dòng, ^nó cũng sẽ loại bỏ các dòng trống trùng lặp.

" 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

Một phương pháp thay thế không sử dụng vi / vim (đối với các tệp rất lớn), là từ dòng lệnh Linux sử dụng sort và uniq:

sort {file-name} | uniq -u

0

Điều này làm việc cho tôi cho cả hai .csv.txt

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

Giải thích: Phần đầu tiên của lệnh in ra các hàng duy nhất và phần thứ hai tức là sau mũi tên ở giữa là để lưu kết quả của phần đầu tiên.

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

>

<newFileName>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.