Vim cari dan ganti teks yang dipilih

109

Katakanlah kita memiliki teks, dan saya memasuki mode visual dan memilih beberapa teks. Bagaimana cara cepat saya menelusuri teks yang disorot dan menggantinya dengan yang lain?

Gabriel Solomon
sumber

Jawaban:

135

Coba lakukan hal berikut atau masukkan ke file .vimrc

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

Dengan menekan ctrl+ rdalam mode visual, Anda akan diminta untuk memasukkan teks yang akan diganti. Tekan enterdan kemudian konfirmasikan setiap perubahan yang Anda setujui yatau tolak n.

Perintah ini akan menimpa register hAnda sehingga Anda dapat memilih yang lain (dengan mengubah hperintah di atas ke huruf kecil lainnya) yang tidak Anda gunakan.

Mykola Golubyev
sumber
13
Jika Anda menghilangkan cin gc, penggantian dilakukan sekaligus di seluruh buffer. Jika Anda membuat kesalahan dan ingin mengembalikannya, cukup ketik umode perintah. Saya menyukai pendekatan ini lebih baik daripada mengkonfirmasi masing-masing penggantian (yang terjadi dengan cpengubah).
Niloct
3
vmap * y:let @/ = @"<CR>dipilih disorot.
kev
8
Apa tujuannya <left><left><left>?
aymericbeaumet
7
@aymericbeaumet untuk mendapatkan kursor di antara dua garis miring ke depan, sehingga kata ganti dapat diketik dengan mudah.
mcabrams
5
Perhatikan bahwa jika Anda menerima saran @ Niloct tentang menghapus cdari gc, Anda juga harus menghapus salah satu dari <left>akhir baris.
Nathan Friend
36

Pencarian pemetaan yang cepat dan sederhana ini untuk teks yang disorot secara visual (tanpa menimpa register h) dan tanpa menggunakan register dependen terminal:

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

Jika Anda tidak suka ctrl-f ubah ke preferensi Anda

Setelah teks disorot, Anda selalu dapat melakukan substitusi hanya dengan mengetik:

%s//<your-replacement-string>

... karena pencarian kosong pada sperintah menggunakan string yang dicari terakhir.

ErichBSchulz
sumber
Ketika saya menggunakan ini dalam konfigurasi vim saya, control+fselalu memilih karakter berikutnya serta apa yang saya pilih secara visual. Ada ide?
Robert Mark Bram
%s//<your-replacement-string>sepertinya tidak berfungsi untuk menyorot sesuatu seperti /tmp/file. itu hanya menjadi<your-replacement-string>/tmp/file
naisanza
28

Yang ini juga berfungsi (setidaknya untuk pilihan dalam satu baris / pilihan yang tidak mengandung karakter khusus)

  • pilih teks dalam mode visual
  • cabut teks dengan y
  • :s/<C-r>0/

0 adalah register yank.

Seperti yang disebutkan orang lain, ada cara yang lebih cepat untuk melakukan ini, tetapi jika Anda baru saja mulai mempelajari Vim (seperti saya), ini adalah salah satu cara 'umum'.

// edit: Saya baru menyadari bahwa pendekatan 'register' akan gagal jika ada karakter seperti tab atau baris baru atau /karakter dalam pemilihan (saya harus memproses karakter tersebut secara manual agar :sperintah berfungsi):

masukkan deskripsi gambar di sini

colemik
sumber
2
Sangat sederhana. Ya Tuhan, mengapa itu tidak tercakup di wiki. Ayo ... Terima kasih atas jawabannya!
Benyamin Limanto
2
Ini adalah jawaban yang ideal bagi kita yang masih berada di bagian awal kurva pembelajaran Vim. Saya tahu kustomisasi adalah kekuatan, tetapi saya tidak ingin menyalin-tempel skrip yang rumit ke dalam vimrc dan teka-teki saya tentang bagaimana itu cocok untuk masalah yang sederhana seperti ini. Jawaban ini mengajari saya bahwa ctrl-R membuang register, yang akan berguna untuk diingat dalam konteks lain.
nivek
26

Jawaban yang diterima berfungsi dengan baik kecuali Anda memiliki karakter khusus dalam pemilihan visual Anda. Saya meretas dua skrip ( Jeremy Cantrell diposting di sini & Peter Odding ) untuk membuat perintah yang memungkinkan Anda untuk memilih secara visual string yang ingin Anda temukan meskipun memiliki karakter regex khusus di dalamnya.

" 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>/

Saya telah memasukkan ini di vimrc saya jika itu lebih berguna bagi siapa pun.

Bryan kennedy
sumber
2
terima kasih atas solusinya, menggabungkan beberapa proposal, saya berakhir dengan yang berikut: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(yang baru saja menggantikan semua dalam file)
Peter Butkovic
13

Dari Vim 7.4, Anda dapat menggunakan gngerakan yang memilih wilayah teks yang cocok dengan pola pencarian saat ini.

Setelah menggunakan cgnuntuk mengubah teks dalam pertandingan yang dipilih saat ini (atau dgnuntuk menghapus), dalam mode normal, Anda dapat menggunakan .untuk mengulangi perintah dan mengoperasikan pertandingan berikutnya.

Ada episode Vimcast yang menampilkan fitur ini.

Dapeng Li
sumber
3
Ini jawaban yang bagus!
mauriciojost
Ini juga luar biasa. selain jawaban colemik. Bagus!
Benyamin Limanto
wow, itu seperti salah satu rahasia yang Anda temukan ketika Anda menjelajah lebih dalam untuk menemukan solusi yang baik, terima kasih!
vdegenne
8

Mykola Golubyev, Terima kasih atas tipnya! Berikut menggunakan register "+" yang (tergantung pada terminal Anda) sudah berisi teks yang disorot, menghemat penggunaan register "h".

vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>
dmd
sumber
VIM 7.0 saya di CentOS 5.x sepertinya tidak memiliki register +. Apakah ini fitur standar?
dotancohen
3
Saya perhatikan bahwa saya mengakses mesin CentOS melalui Putty, dan setelah googling saya melihat bahwa + adalah register clipboard. Putty sepertinya tidak mendukung itu! Jadi jawaban ini sebenarnya bergantung pada terminal.
dotancohen
Hai, saya mencoba perintah Anda tetapi meminta saya untuk mengganti kemunculan teks tertentu di seluruh file, dan bukan hanya teks yang dipilih
solalito
7

Dari http://vim.wikia.com/wiki/Search_and_replace_in_a_visual_selection :

Saat teks dipilih secara visual, tekan: untuk memasukkan perintah. Baris perintah secara otomatis akan memasuki kisaran:

:'<,'>

Anda dapat memasukkan perintah seperti s / red / green / g untuk mengganti setiap merah dengan hijau di semua baris pemilihan visual terakhir. Perintah akan muncul sebagai:

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

Untuk mengulangi perintah Ex di atas blok yang dipilih sebelumnya, gunakan: history. Yaitu, tekan: lalu, lalu edit perintah sebelumnya.

syvex
sumber
4
ya ini menggantikan merah dengan hijau di area yang dipilih - sangat berguna, tapi bukan apa yang diminta op.
ErichBSchulz
@ErichBSchulz Ini sebenarnya melakukannya di semua baris yang dipilih. Jadi, meskipun hanya sebagian dari garis yang dipilih, itu akan dilakukan ke seluruh garis.
Cully
1
Mungkin itu tidak menjawab pertanyaan OP, tapi ini benar-benar menjawab pencarian saya "pencarian vim dan ganti dengan pemilihan visual", di mana saya ingin membatasi pencarian dan mengganti hanya pemilihan visual, yang memunculkan pertanyaan ini
icc97
5

Saya memiliki ini di vimrc saya:

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>/

Ini akan mengambil pilihan visual dan memulai perintah substitusi dengannya.

EDIT: Saya harus menunjukkan bahwa ini tidak berfungsi dengan pilihan visual multiline. Meskipun GetVisual () tidak memiliki masalah mengembalikannya, saya tidak yakin bagaimana memasukkannya ke dalam baris perintah dengan benar. Jika ada yang punya tip tentang bagaimana saya bisa melakukan ini, tolong beri komentar.

Jeremy Cantrell
sumber
2

Saya tidak berpikir Anda bisa melakukan ini di luar kotak. Tetapi banyak orang menyukai fitur ini, jadi ada banyak sekali makro dan semacamnya (saya telah menambahkannya sendiri). Ini salah satu yang bisa Anda tambahkan, misalnya; cukup tekan *untuk mencari kecocokan berikutnya pada teks yang dipilih secara visual.

John Feminella
sumber
2

Jawaban lain bagus tetapi tidak luput dari karakter khusus. The jawaban dari @ Brian kennedy menunjukkan metode untuk melarikan diri tetapi membutuhkan banyak kode. Dalam kasus URL misalnya, melarikan diri adalah wajib atau pencarian akan berhenti di ":".

Seperti yang tertulis di vim.fandom.com/wiki/Search_for_visually_selected_text , Anda dapat melakukan oneliner untuk mencari dan melepaskan beberapa karakter. Anda dapat melarikan diri dari karakter yang Anda inginkan, saya memilih untuk melarikan diri /\: :

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

Dengan peta ini, saya harus menekan //dalam mode visual untuk mencari teks yang sedang dipilih di seluruh buffer.

RomainTT
sumber
1

Versi pendek favorit saya adalah

vnoremap s / y: s / "/

Kemudian Anda dapat menyorot sebuah pilihan dan tekan saja s / untuk memulai perintah substitusi untuknya.

alex
sumber
Tidak berhasil untuk saya, diperlakukan "sebagai literal. <c-r>"bekerja meskipun
Josh Bodah
1

Saya tidak memiliki perwakilan untuk berkomentar, jadi saya menambahkan jawaban lain ...

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

@dmd dan @dotancohen: ini bekerja untuk saya tanpa menggunakan habis "h(secara eksplisit menggunakan 0, yang merupakan posisi yank terakhir) dan bekerja dengan putty ssh -> mint (lmde); tidak tahu tentang sen. Juga menggunakan komentar @Niloct dan @Nathan Friend untuk menghapus konfirmasi.

10'004
sumber
1

Contoh 1. Pemilihan kutipan dengan bintang, pertahankan kursor di awal pemilihan.

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

Contoh 2. Pipa teks yang dipilih dengan base64:

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

Penjelasan LHS:

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

Penjelasan RHS:

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

Saya berharap ada cara built-in di Vim untuk menggantikan kata, tanpa harus mengetik ulang kata itu di tempat pertama. Ada, meski hanya akan berfungsi untuk teks hingga karakter batas kata.

Setelah Anda mengarahkan mouse ke kata tersebut, tekan *atau #untuk menyorot kata dan lompat ke lokasi berikutnya / sebelumnya (jika Anda tidak ingin mengubah lokasi di file, lalu tekan tombol yang berlawanan untuk kembali ke lokasi kamu baru saja di).

Kemudian ketik saja:

%s//<your-replacement-string>

Seperti yang disebutkan dalam jawaban orang lain, jika %smenerima entri kosong di antara garis miring, maka kata tersebut menggunakan kata yang telah dicari sebelumnya. Dengan menekan *atau #, Anda mencari kata di bawah kursor yang menjadikannya kata yang paling baru dicari.

Pada akhirnya, hanya enam atau tujuh penekanan tombol + panjang kata pengganti untuk melakukan ini dan tidak memerlukan makro atau pengeditan file .vimrc.

Cameron Gagnon
sumber