Vim: làm thế nào để xóa mọi hàng thứ hai?


Câu trả lời:


105

Bạn có thể sử dụng macro cho việc này. Làm như sau.

  • Bắt đầu ở chế độ lệnh.
  • Đi tới đầu tệp bằng cách nhấn gg.
  • Nhấn qq.
  • Nhấp vào mũi tên xuống và nhấn ddsau.
  • Nhấn q.
  • nhấn 10000@q

Tái bút: Để chuyển sang chế độ lệnh chỉ cần nhấn Escape một vài lần.


11
Giả sử tập tin của bạn được ít hơn 20.000 dòng dài tất nhiên :-)
paxdiablo

3
Thực ra bạn nhầm rồi Michael. Điều này hoạt động hoàn hảo vì VI sẽ ngừng chạy macro ngay sau khi nó chạm đến cuối tệp. Bạn có thể rất dễ dàng dùng thử với mẫu trên.
rui

1
Chà, giống như bất kỳ macro nào, bạn cần có nó ngay lần đầu tiên nhưng sau đó, bạn có thể áp dụng cho bất kỳ tệp nào bằng cách chỉ cần nhập 10000 @ q. Dù thế nào thì tôi tin rằng đó chỉ là vấn đề thị hiếu nên tôi chắc chắn sẽ không bắt đầu một cuộc tranh luận triết học. :)
rui

3
Tôi thích sử dụng 'macro' hơn. Sử dụng macro, bạn 'mô tả' cách bạn sẽ giải quyết một nhiệm vụ cụ thể và để VIM lặp lại nó cho bạn. RUI, tôi muốn sử dụng 'j' thay vì phím mũi tên.
SolutionYogi

4
:g/^/+dtừ user stackoverflow.com/users/254635/ib (dưới đây) là cách giải quyết vấn đề này một cách thanh lịch hơn.
SergioAraujo

254

Một cách thanh lịch (và hiệu quả) để hoàn thành nhiệm vụ là gọi :+deletelệnh xóa dòng theo sau dòng hiện tại, trên mọi dòng bằng :globallệnh:

:g/^/+d

10
Tại sao câu trả lời này không nhận được nhiều phiếu bầu hơn? Điều này rất sạch sẽ và đơn giản. Ngoài ra, bạn có thể xóa dòng đầu tiên và chạy lệnh trên để xóa tất cả các dòng lẻ.
Usagi

3
@Usagi: Cảm ơn bạn! Tôi cảm thấy như vậy về nó. Và vâng, bạn hoàn toàn đúng, :1d|g/^/+dxóa các dòng lẻ.
ib.

@Usagi Câu trả lời còn lại đã được chọn là 'câu trả lời hay nhất' 2 năm trước khi câu trả lời của anh ấy xuất hiện. Ngoài ra, mặc dù đây là một giải pháp thanh lịch hơn, nó có thể được viết theo một cách hữu ích hơn (tức là không đề cập đến những gì ^ làm, trong khi macro rất dễ hiểu đối với bất kỳ ai).
user1271772

3
Xin lỗi, nhưng không có lời giải thích về cách lệnh đó thực hiện hành vi mong muốn, tôi sẽ không tán thành nó và thay vào đó thích câu trả lời được chấp nhận hơn, vì tôi hiểu cách nó hoàn thành mục tiêu. Đó là sự khác biệt giữa việc cho một người đàn ông một con cá và dạy anh ta cách câu cá.
Gabe

3
Tôi không biết, câu trả lời này khiến tôi phải ra ngoài và học cách câu cá bằng lệnh: g (nghĩa là, nó khiến tôi google trang này - vim.wikia.com/wiki/Power_of_g ).
snetch

67

Chúng ta có thể sử dụng :normalhoặc :normthực hiện các lệnh chế độ bình thường đã cho. Nguồn.

:%norm jdd

15
Câu trả lời này không được chú ý đầy đủ, có thể do thiếu phần giải thích cả ở đây và trên bảng lừa đảo, lộn xộn, được liên kết. lệnh định mức chạy các lệnh chế độ bình thường tương đương với các chữ cái theo sau nó. Vì vậy, ở đây nó đang chạy j để di chuyển xuống một dòng và dd để xóa nó. Điều này có thể được tổng quát hóa cho dòng thứ X bằng cách thêm nhiều 'j hơn trong trường hợp này.
imoatama

5
và% là viết tắt cho 1, $ (thực hiện lệnh sau từ dòng 1 đến cùng)
Lambart

3
Tôi quan tâm đến lý do tại sao %norm ddjkhông hoạt động nếu bạn muốn xóa các hàng lẻ.
Cyker

10
:map ^o ddj^o
^o

Đây ^ là viết tắt của CTRL. Macro đệ quy để xóa một dòng sau mỗi hai dòng. Chọn tốt dòng đầu tiên của bạn và nó đã hoàn thành.


8

từ kho lưu trữ thư vim :

:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile

(Được gõ trên một dòng trên dòng lệnh vim, sẽ xóa hàng 1,3,5,7, ...)


4
Sau đó, tôi muốn !perl -ne 'print unless $. % 2':-)
Alex Brasetvik

Và, Alex, tôi chắc chắn thích giải pháp của tôi hơn giải pháp của bạn, nhưng giải pháp này đáng xem xét vì đây là giải pháp hợp lý duy nhất chỉ sử dụng chính vim ở đây.
Michael Krelin - hacker

Cách vĩ mô dễ dàng hơn nhiều.
trusktr

+1 vì tính linh hoạt if (expression)mà cũng hoạt động với mọi dòng thứ ba, v.v.
Jens

5

Bạn luôn có thể chuyển qua lệnh shell, có nghĩa là bạn có thể sử dụng bất kỳ ngôn ngữ kịch bản nào bạn thích:

:%!perl -nle 'print if $. % 2'

(hoặc sử dụng "trừ khi" thay vì "nếu", tùy thuộc vào dòng nào bạn muốn)


Bạn không cần phải -lchuyển sang Perl ... ngoài ra, tôi muốn nói rằng nó awkphổ biến hơn Perl một chút, mặc dù nó không thực sự nhiều hơn những ngày này và có thể làm điều này ngắn hơn:, :%!awk NR\%2hoặc :%!awk 1-NR\%2đối với các dòng khác.
ephemient

4
:%!awk -- '++c\%2'

cách khác

:%!awk -- 'c++\%2'

tùy thuộc vào nửa mà bạn muốn loại bỏ.


Umm, tại sao không sử dụng NRbiến hiện có ?
ephemient

Đúng. Bởi vì tôi đã quên mất nó. ;-) Nhưng trên thực tế, biến thể "thích hợp" sẽ còn dài hơn với NR. Và sẽ không có hai đối tác đẹp mắt .
Michael Krelin - hacker

:%!awk NR\%2hoặc :%!awk 1-NR\%2, như tôi đã đăng trong một bình luận khác. Điều đó hầu như không lâu hơn.
ephemient

1
1-NRdài hơn c++. Vâng, tôi biết đó là một nhân vật. Như tôi đã nói - lý do thực sự là tôi đã quên mất nó. Dù sao, có vẻ như mọi người không đánh giá cao vẻ đẹp của awk ở đây.
Michael Krelin - hacker

NRngắn hơn ++c:)
ephemient

3

Bạn có thể sử dụng các khả năng tìm kiếm và thay thế của chính Vim như sau: Đặt con trỏ của bạn ở dòng đầu tiên và nhập ở chế độ bình thường:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • Các .,/fff/là phạm vi sử dụng quyền thay người. Nó có nghĩa là "từ dòng này đến dòng khớp với regex fff(trong trường hợp này là dòng cuối cùng).
  • s///là lệnh thay thế. Nó tìm kiếm một regex và thay thế mọi lần xuất hiện của nó bằng một chuỗi. Ở gcuối có nghĩa là lặp lại sự thay thế miễn là regex vẫn được tìm thấy.
  • Regex \n.*\(\n.*\)khớp với một dòng mới, sau đó .*khớp với toàn bộ dòng ( khớp với bất kỳ số ký tự nào ngoại trừ một dòng mới), rồi đến một dòng mới và một dòng khác. Dấu ngoặc đơn \(\)ghi lại biểu thức bên trong chúng, vì vậy chúng ta có thể sử dụng nó sau này \1.
  • \1 chèn dòng mới đã nhóm và dòng sau nó trở lại, bởi vì chúng tôi không muốn dòng tiếp theo cũng biến mất - chúng tôi chỉ muốn cơ chế thay thế đi qua nó để chúng tôi không xóa nó trong lần thay thế tiếp theo.

Bằng cách này, bạn có thể kiểm soát phạm vi mà bạn muốn xóa diễn ra và bạn không phải sử dụng bất kỳ công cụ bên ngoài nào.


Hoặc $thay vì /fff/, đối với phần cuối của tệp bất kể nội dung của tệp.
ephemient

3

Như một cách tiếp cận khác, bạn cũng có thể sử dụng python nếu vim của bạn có hỗ trợ cho nó.

:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]

b = cb[:]sao chép tạm thời tất cả các dòng trong bộ đệm hiện tại sang b. b[::2]lấy mỗi dòng thứ hai từ bộ đệm và gán nó cho toàn bộ bộ đệm hiện tại cb[:]. Bản sao tới blà cần thiết vì các đối tượng đệm dường như không hỗ trợ cú pháp lát cắt mở rộng.

Đây có lẽ không phải là "vim way", nhưng có thể dễ nhớ hơn nếu bạn biết python.


2

Để xóa các dòng lẻ (1,3,5, ..) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

Để xóa các dòng chẵn (2,4,6, ..) -> :%s/\(.*\)\n.*\n/\1\r/g

Tìm kiếm văn bản (tạo dòng đầu tiên) theo sau là một ký tự dòng mới và một số văn bản khác (tạo dòng thứ hai), theo sau là một ký tự dòng mới khác và thay thế ở trên bằng kết hợp đầu tiên (dòng lẻ) hoặc kết hợp thứ hai (dòng chẵn) tiếp theo là ký tự xuống dòng.


0

Gọi sed:

:% !sed -e '2~2 d'

^^^^                  pipe file through a shell command
    ^^^^^^            the command is sed, and -e describes an expression as parameter
            ^^^^^     starting with the second line, delete every second line

-1

giải pháp

bạn có thể thử điều này trong vim

:1,$-1g/^/+1d

biên tập

Tôi sẽ cố gắng nói rõ hơn (hai phần)

phần đầu tiên phạm vi lựa chọn ( :from,to)
phần thứ hai hành động ( dxóa)

  • phạm vi nếu từ dòng đầu tiên đến dòng cuối cùng trừ một dòng ( :1,$-1)
  • globaly ( g) delete ( +1d) dòng tiếp theo

bạn có thể cố gắng di chuyển đến dòng đầu tiên của tệp và thực thi, :+1dbạn sẽ thấy dòng tiếp theo biến mất

Tôi biết nó là bùn, nhưng đó là khí lực và nó hoạt động


Trong như bùn. Cảm ơn!
Henry Henrinson
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.