Vim tìm kiếm và thay thế văn bản đã chọn


109

Giả sử chúng ta có một văn bản và tôi vào chế độ trực quan và chọn một số văn bản. Làm cách nào để nhanh chóng thực hiện tìm kiếm văn bản được đánh dấu và thay thế nó bằng văn bản khác?

Câu trả lời:


135

Hãy thử thực hiện những điều sau đây hoặc đưa vào .vimrc

vnoremap <C-r> "hy:%s/<C-r>h//gc<left><left><left>

Bằng cách nhấn ctrl+ rở chế độ trực quan, bạn sẽ được nhắc nhập văn bản để thay thế bằng. Nhấn entervà sau đó xác nhận từng thay đổi bạn đồng ý yhoặc từ chối n.

Lệnh này sẽ ghi đè lên thanh ghi của bạn hđể bạn có thể chọn một thanh ghi khác (bằng cách thay đổi htrong lệnh trên thành một ký tự viết thường khác) mà bạn không sử dụng.


13
Nếu bạn bỏ qua ctrong gc, thay thế được thực hiện cùng một lúc trong toàn bộ đệm. Nếu bạn mắc lỗi và muốn hoàn nguyên, chỉ cần nhập uvào chế độ lệnh. Tôi thích cách tiếp cận này hơn là xác nhận từng thay thế (điều đó xảy ra với công cụ csửa đổi).
Niloct

3
vmap * y:let @/ = @"<CR>đã chọn được đánh dấu.
kev

8
Mục tiêu là <left><left><left>gì?
aymericbeaumet

7
@aymericbeaumet để đưa con trỏ vào giữa hai dấu gạch chéo về phía trước, bằng cách đó, từ thay thế có thể dễ dàng nhập.
mcabrams

5
Lưu ý rằng nếu bạn thực hiện đề xuất của @ Niloct về việc xóa ctừ gc, bạn cũng sẽ phải xóa một trong các <left>từ ở cuối dòng.
Nathan Friend,

36

Tìm kiếm ánh xạ nhanh chóng và đơn giản này cho văn bản được đánh dấu trực quan (không ghi đè thanh ghi h) và không sử dụng thanh ghi + phụ thuộc đầu cuối:

" search for visually hightlighted text
vnoremap <c-f> y<ESC>/<c-r>"<CR>   

Nếu bạn không thích ctrl-f, hãy thay đổi nó theo sở thích của bạn

Sau khi văn bản được đánh dấu, bạn luôn có thể thực hiện sthay đổi đơn giản bằng cách gõ:

%s//<your-replacement-string>

... bởi vì tìm kiếm trống trên slệnh sử dụng chuỗi được tìm kiếm cuối cùng.


Khi tôi sử dụng điều này trong cấu hình vim của mình, hãy control+fluôn chọn nhân vật tiếp theo cũng như những gì tôi đã chọn trực quan. Bất kỳ ý tưởng?
Robert Mark Bram

%s//<your-replacement-string>dường như không hoạt động để làm nổi bật một cái gì đó giống như /tmp/file. nó chỉ trở nên<your-replacement-string>/tmp/file
naisanza

28

Điều này cũng hoạt động (ít nhất là đối với các lựa chọn trong một dòng / các lựa chọn không chứa bất kỳ ký tự đặc biệt nào)

  • chọn văn bản ở chế độ trực quan
  • kéo văn bản với y
  • :s/<C-r>0/

0 là thanh ghi yank.

Như những người khác đã đề cập, có nhiều cách nhanh hơn để làm điều này, nhưng nếu bạn mới bắt đầu học Vim (như tôi), đây là một trong những cách 'chung chung'.

// chỉnh sửa: Tôi vừa nhận ra rằng cách tiếp cận 'đăng ký' sẽ không thành công nếu có các ký tự như tab hoặc dòng mới hoặc /ký tự trong vùng chọn (tôi phải xử lý thủ công các ký tự đó bằng cách nào đó để :slệnh hoạt động):

nhập mô tả hình ảnh ở đây


2
Nó rất đơn giản. Ôi Chúa ơi, tại sao nó không được đưa lên wiki. Cố lên ... Cảm ơn bạn đã trả lời!
Benyamin Limanto

2
Đây là câu trả lời lý tưởng cho những ai trong chúng ta vẫn còn ở giai đoạn đầu của lộ trình học Vim. Tôi biết tùy chỉnh là một thế mạnh, nhưng tôi không muốn sao chép-dán một tập lệnh phức tạp vào vimrc của mình và giải đố xem nó khớp với nhau như thế nào cho một vấn đề đơn giản như thế này. Câu trả lời này đã dạy tôi rằng ctrl-R kết xuất một thanh ghi, điều này sẽ hữu ích để ghi nhớ trong các ngữ cảnh khác.
nivek

26

Câu trả lời được chấp nhận hoạt động tốt trừ khi bạn có các ký tự đặc biệt trong lựa chọn hình ảnh của mình. Tôi đã kết hợp hai tập lệnh (của Jeremy Cantrell được đăng ở đây và của Peter Odding ) để tạo một lệnh cho phép bạn chọn trực quan một chuỗi mà bạn muốn tìm ngay cả khi nó có các ký tự regex đặc biệt trong đó.

" Escape special characters in a string for exact matching.
" This is useful to copying strings from the file to the search tool
" Based on this - http://peterodding.com/code/vim/profile/autoload/xolox/escape.vim
function! EscapeString (string)
  let string=a:string
  " Escape regex characters
  let string = escape(string, '^$.*\/~[]')
  " Escape the line endings
  let string = substitute(string, '\n', '\\n', 'g')
  return string
endfunction

" Get the current visual block for search and replaces
" This function passed the visual block through a string escape function
" Based on this - /programming/676600/vim-replace-selected-text/677918#677918
function! GetVisual() range
  " Save the current register and clipboard
  let reg_save = getreg('"')
  let regtype_save = getregtype('"')
  let cb_save = &clipboard
  set clipboard&

  " Put the current visual selection in the " register
  normal! ""gvy
  let selection = getreg('"')

  " Put the saved registers and clipboards back
  call setreg('"', reg_save, regtype_save)
  let &clipboard = cb_save

  "Escape any special characters in the selection
  let escaped_selection = EscapeString(selection)

  return escaped_selection
endfunction

" Start the find and replace command across the entire file
vmap <leader>z <Esc>:%s/<c-r>=GetVisual()<cr>/

Tôi đã đưa cái này vào vimrc của mình nếu nó hữu ích hơn cho bất kỳ ai.


2
cảm ơn vì giải pháp, kết hợp nhiều kiến nghị, tôi đã kết thúc với những điều sau đây: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(mà chỉ thay thế tất cả trong tập tin)
Peter Butkovic

13

Từ Vim 7.4, bạn có thể sử dụng gn chuyển động để chọn các vùng văn bản phù hợp với mẫu tìm kiếm hiện tại.

Sau khi sử dụng cgnđể thay đổi văn bản trong kết quả phù hợp hiện được chọn (hoặc dgnđể xóa), ở chế độ bình thường, bạn có thể sử dụng. để lặp lại lệnh và thao tác trên khớp tiếp theo.

một tập Vimcast hiển thị tính năng này.


3
Đây là một câu trả lời tuyệt vời!
mauriciojost

Điều này cũng tuyệt vời. ngoài câu trả lời colemik. Tuyệt vời!
Benyamin Limanto

wow, nó giống như một trong những bí mật bạn tìm thấy khi duyệt sâu để tìm ra giải pháp tốt, cảm ơn!
vdegenne

8

Mykola Golubyev, Cảm ơn vì mẹo! Sau đây sử dụng thanh ghi "+" (tùy thuộc vào thiết bị đầu cuối của bạn) đã chứa văn bản được đánh dấu, tiết kiệm từ việc sử dụng thanh ghi "h".

vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>

VIM 7.0 của tôi trên CentOS 5.x dường như không có + đăng ký. Đây có phải là một tính năng tiêu chuẩn không?
dotancohen

3
Tôi lưu ý rằng tôi truy cập máy CentOS thông qua Putty và trên googling, tôi thấy rằng + là thanh ghi clipboard. Putty dường như không ủng hộ điều đó! Vì vậy, câu trả lời này trên thực tế phụ thuộc vào thiết bị đầu cuối.
dotancohen

Hi, tôi đã cố gắng lệnh của bạn, nhưng nó được yêu cầu tôi thay thế các lần xuất hiện của văn bản quy định trên khắp tất cả các tập tin, và không chỉ là văn bản đã chọn
solalito

7

Từ http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection :

Khi văn bản được chọn trực quan, hãy nhấn: để nhập lệnh. Dòng lệnh sẽ tự động nhập phạm vi:

:'<,'>

Bạn có thể nhập một lệnh như s / red / green / g để thay thế từng màu đỏ bằng màu xanh lá cây trong tất cả các dòng của lựa chọn trực quan cuối cùng. Lệnh sẽ xuất hiện dưới dạng:

:'<,'>s/red/green/g

Để lặp lại lệnh Ex trên một khối đã chọn trước đó, hãy sử dụng: history. Tức là, nhấn: then, sau đó chỉnh sửa một lệnh trước đó.


4
có điều này thay thế màu đỏ bằng màu xanh lá cây trong khu vực đã chọn - rất hữu ích, nhưng không phải những gì op yêu cầu.
ErichBSchulz

@ErichBSchulz Nó thực sự làm được điều đó trên tất cả các dòng được chọn. Vì vậy, ngay cả khi chỉ một phần của dòng được chọn, nó sẽ làm điều đó cho toàn bộ dòng.
Cully

1
Có lẽ nó không trả lời câu hỏi OP, nhưng điều này trả lời chính xác tìm kiếm của tôi "tìm kiếm vim và thay thế bằng lựa chọn trực quan", nơi tôi muốn giới hạn tìm kiếm và thay thế chỉ để lựa chọn trực quan, dẫn đến câu hỏi này
icc97

5

Tôi có cái này trong vimrc của mình:

function! GetVisual() range
    let reg_save = getreg('"')
    let regtype_save = getregtype('"')
    let cb_save = &clipboard
    set clipboard&
    normal! ""gvy
    let selection = getreg('"')
    call setreg('"', reg_save, regtype_save)
    let &clipboard = cb_save
    return selection
endfunction

vmap <leader>z :%s/<c-r>=GetVisual()<cr>/

Thao tác này sẽ lấy lựa chọn trực quan và bắt đầu lệnh thay thế với nó.

CHỈNH SỬA: Tôi nên chỉ ra rằng điều này không hoạt động với các lựa chọn trực quan nhiều dòng. Mặc dù GetVisual () không gặp sự cố khi trả lại nó, nhưng tôi không chắc cách đặt nó vào dòng lệnh một cách chính xác. Nếu bất kỳ ai có bất kỳ mẹo nào về cách tôi có thể làm điều này, vui lòng bình luận.


2

Tôi không nghĩ rằng bạn có thể làm điều này ngay lập tức. Nhưng rất nhiều người thích tính năng này, vì vậy có rất nhiều macro và những thứ như vậy (tôi đã tự thêm nó). Đây là một ví dụ bạn có thể thêm; chỉ cần nhấn *để tìm kiếm kết quả phù hợp tiếp theo trên văn bản được chọn trực quan.


2

Các câu trả lời khác là tốt nhưng chúng không thoát khỏi các ký tự đặc biệt. Câu trả lời của @brian kennedy cho thấy một phương pháp để thoát nhưng nó đòi hỏi nhiều mã. Trong trường hợp một URL chẳng hạn, việc thoát là bắt buộc hoặc quá trình tìm kiếm sẽ dừng lại trên “:”.

Như được viết trong vim.fandom.com/wiki/Search_for_visently_selected_text , bạn có thể thực hiện oneliner để tìm kiếm và thoát một số ký tự. Bạn có thể thoát khỏi các ký tự mà bạn muốn, tôi đã chọn thoát /\: :

vnoremap // y/\V<C-R>=escape(@",'/\:')<CR><CR>

Với bản đồ này, tôi phải nhấn //ở chế độ trực quan để tìm kiếm văn bản đang được chọn trên toàn bộ bộ đệm.


1

Phiên bản ngắn yêu thích của tôi về cái này là

vnoremap s / y: s / "/

Sau đó, bạn có thể đánh dấu một lựa chọn và chỉ cần nhấn s / để bắt đầu lệnh thay thế cho nó.


Không hiệu quả với tôi, được coi "như một nghĩa đen. <c-r>"đã làm việc mặc dù
Josh Bodah

1

Tôi không có đại diện để bình luận, vì vậy tôi đang thêm một câu trả lời khác ...

vnoremap <C-r> "0y<Esc>:%s/<C-r>0//g<left><left>

@dmd và @dotancohen: điều này phù hợp với tôi mà không cần sử dụng hết "h(rõ ràng sử dụng 0, dù sao cũng là vị trí cuối cùng) và hoạt động với putty ssh -> mint (lmde); không biết về xu. Đồng thời sử dụng nhận xét của @Niloct và @Nathan Friend để xóa xác nhận.


1

Ví dụ 1. Trích dẫn lựa chọn với các dấu sao, giữ con trỏ khi bắt đầu lựa chọn.

:%s,\%#\%V\_.*\%V/,**&**,c 

Ví dụ 2. Đặt văn bản đã chọn với base64:

:%s!\%#\%V\_.*\%V!\=system("base64 -w 0",@")!c

LHS giải thích:

\%# matches cursor 
\%V matches inside the selection only
\_. matches any character.
\_.* matches beginning to end of selection.

Giải thích RHS:

\=expr()  Replace match with result of expr() for each substitution.

0

Tôi đã hy vọng có một cách được xây dựng trong Vim để thay thế một từ mà không cần phải gõ lại từ đó ngay từ đầu. Có, mặc dù nó sẽ chỉ hoạt động cho văn bản tối đa một ký tự ranh giới từ.

Khi bạn đã di chuột qua từ, hãy nhấn *hoặc #để đánh dấu từ đó và chuyển đến vị trí tiếp theo / trước đó của từ đó (nếu bạn không muốn thay đổi vị trí trong tệp, sau đó nhấn phím đối diện để quay lại vị trí bạn vừa ở).

Sau đó, chỉ cần nhập:

%s//<your-replacement-string>

Như đã đề cập trong câu trả lời của người khác, nếu %snhận được một mục trống giữa các dấu gạch chéo, thì nó sẽ sử dụng từ đã tìm kiếm trước đó. Bằng cách nhấn *hoặc #, bạn đang tìm kiếm từ bên dưới con trỏ, từ đó biến nó thành từ được tìm kiếm gần đây nhất.

Cuối cùng, chỉ có sáu hoặc bảy lần nhấn phím + độ dài của từ thay thế để thực hiện điều này và nó không yêu cầu macro hoặc chỉnh sửa của bạn .vimrc.

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.