Vim cerca e sostituisce il testo selezionato


109

Diciamo che abbiamo un testo e che entri in modalità visuale e seleziono del testo. Come faccio a cercare rapidamente il testo evidenziato e lo sostituisco con qualcos'altro?

Risposte:


135

Prova a eseguire quanto segue o inseriscilo nel tuo file .vimrc

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

Premendo ctrl+ rin modalità visuale, ti verrà chiesto di inserire il testo da sostituire con. Premere entere quindi confermare ogni modifica che si accetta yo con cui si rifiuta n.

Questo comando sovrascriverà il tuo registro in hmodo che tu possa sceglierne un altro (cambiando hnel comando sopra con un'altra lettera minuscola) che non usi.


13
Se si omette l' cin gc, la sostituzione viene eseguita immediatamente nell'intero buffer. Se hai commesso un errore e desideri ripristinarlo, digita semplicemente uin modalità di comando. Mi piace questo approccio di più rispetto alla conferma di ciascuna delle sostituzioni (che accade con il cmodificatore).
Niloct

3
vmap * y:let @/ = @"<CR>selezionato è evidenziato.
kev

8
Qual è l'obiettivo di <left><left><left>?
aymericbeaumet

7
@aymericbeaumet per ottenere il cursore tra le due barre in avanti, in questo modo la parola di sostituzione può essere facilmente digitata.
mcabrams

5
Nota che se segui il suggerimento di @ Niloct sulla rimozione di cda gc, dovrai anche rimuovere uno dei <left>alla fine della riga.
Nathan Friend

36

Questa mappatura rapida e semplice ricerca il testo evidenziato visivamente (senza sovrascrivere il registro h) e senza utilizzare il registro + dipendente dal terminale:

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

Se non ti piace il ctrl-f modificalo in base alle tue preferenze

Una volta che il testo è evidenziato puoi sempre fare una ssostituzione semplicemente digitando:

%s//<your-replacement-string>

... perché una ricerca vuota sul scomando utilizza l'ultima stringa cercata.


Quando lo uso nella mia configurazione vim, control+fseleziona sempre il personaggio successivo oltre a quello che ho selezionato visivamente. Qualche idea?
Robert Mark Bram

%s//<your-replacement-string>non sembra funzionare per evidenziare qualcosa di simile /tmp/file. diventa solo<your-replacement-string>/tmp/file
naisanza

28

Anche questo funziona (almeno per le selezioni in una singola riga / selezioni che non contengono caratteri speciali)

  • seleziona il testo in modalità visuale
  • trascina il testo con y
  • :s/<C-r>0/

0 è il registro degli strattoni.

Come altre persone hanno detto, ci sono modi più veloci per farlo, ma se hai appena iniziato a imparare Vim (come me), questo è uno dei modi "generici".

// modifica: mi sono appena reso conto che l'approccio 'register' fallirà se ci sono caratteri come tabulazioni o newline o /caratteri nella selezione (dovrei elaborare manualmente quei caratteri in qualche modo affinché il :scomando funzioni):

inserisci qui la descrizione dell'immagine


2
È molto semplice. Oh Dio, perché non è trattato sul wiki. Dai ... Grazie per la risposta!
Benyamin Limanto

2
Questa è la risposta ideale per quelli di noi ancora nella prima parte della curva di apprendimento di Vim. So che la personalizzazione è un punto di forza, ma non voglio copiare e incollare uno script complesso nel mio vimrc e capire come si adatta a un problema così semplice. Questa risposta mi ha insegnato che ctrl-R scarica un registro, che sarà utile da ricordare in altri contesti.
nivek

26

La risposta accettata funziona alla grande a meno che tu non abbia caratteri speciali nella tua selezione visiva. Ho hackerato insieme due script (quello di Jeremy Cantrell pubblicato qui e quello di Peter Odding ) per creare un comando che ti permetta di selezionare visivamente una stringa che vuoi trovare anche se contiene caratteri speciali regex.

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

L'ho incluso nel mio vimrc se è più utile per chiunque.


2
grazie per la soluzione, combinando più proposte, ho finito con il seguente: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(che sostituisce solo tutto nel file)
Peter Butkovic

13

Da Vim 7.4, puoi usare il gnmovimento che seleziona regioni di testo che corrispondono allo schema di ricerca corrente.

Dopo aver utilizzato cgnper modificare il testo nella corrispondenza attualmente selezionata (o dgnper eliminare), in modalità normale, è possibile utilizzare .per ripetere il comando e operare sulla corrispondenza successiva.

C'è un episodio di Vimcast che mostra questa funzione.


3
Questa è un'ottima risposta!
mauriciojost

Anche questo è fantastico. a parte la risposta di colemik. Grande!
Benyamin Limanto,

wow, è come uno di quei segreti che trovi quando navighi in profondità per trovare una buona soluzione, grazie!
vdegenne

8

Mykola Golubyev, grazie per il suggerimento! Di seguito utilizza il registro "+" che (a seconda del terminale) contiene già il testo evidenziato, salvo utilizzando il registro "h".

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

Il mio VIM 7.0 su CentOS 5.x non sembra avere il registro +. È una caratteristica standard?
dotancohen

3
Noto che accedo alla macchina CentOS tramite Putty e su Google vedo che + è il registro degli appunti. Putty non sembra supportarlo! Quindi questa risposta è in effetti dipendente dal terminale.
dotancohen

Ciao, ho provato il tuo comando ma mi sta chiedendo di sostituire le occorrenze del testo specificato in tutto il file, e non solo il testo selezionato
solalito

7

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

Quando il testo è selezionato visivamente, premere: per immettere un comando. La riga di comando entrerà automaticamente nell'intervallo:

:'<,'>

È possibile immettere un comando come s / red / green / g per sostituire ogni rosso con verde in tutte le righe dell'ultima selezione visiva. Il comando apparirà come:

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

Per ripetere un comando Ex su un blocco selezionato in precedenza, utilizzare: history. Cioè, premere: quindi, quindi modificare un comando precedente.


4
sì, questo sostituisce il rosso con il verde nell'area selezionata - molto utile, ma non quello richiesto dall'operazione.
ErichBSchulz

@ErichBSchulz In realtà lo fa su tutte le linee selezionate. Quindi, anche se è selezionata solo una parte di una linea, lo farà per l'intera linea.
Cully

1
Forse non risponde alla domanda OP, ma questo risponde esattamente alla mia ricerca "vim cerca e sostituisci con selezione visiva", dove voglio limitare la ricerca e sostituire solo alla selezione visiva, il che fa apparire questa domanda
icc97

5

Ho questo nel mio vimrc:

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

Questo afferrerà la selezione visiva e avvierà un comando di sostituzione con essa.

EDIT: vorrei sottolineare che questo non funziona con selezioni visive multilinea. Sebbene GetVisual () non abbia problemi a restituirlo, non sono sicuro di come inserirlo correttamente nella riga di comando. Se qualcuno ha dei suggerimenti su come potrei farlo, per favore commenta.


2

Non credo che tu possa farlo fuori dagli schemi. Ma a molte persone piace questa funzione, quindi ci sono tonnellate di macro e simili (l'ho aggiunto io stesso). Eccone uno che puoi aggiungere, ad esempio; basta premere *per cercare la corrispondenza successiva sul testo selezionato visivamente.


2

Altre risposte sono buone ma non sfuggono ai caratteri speciali. La risposta di @brian kennedy mostra un metodo per fuggire ma richiede molto codice. Nel caso di un URL, ad esempio, l'escape è obbligatorio o la ricerca si fermerà su ":".

Come scritto in vim.fandom.com/wiki/Search_for_visually_selected_text , puoi fare un oneliner per cercare ed eseguire l'escape di alcuni caratteri. Puoi sfuggire ai personaggi che vuoi, ho scelto di scappare /\: :

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

Con questa mappa, devo premere //in modalità visuale per cercare il testo attualmente selezionato sull'intero buffer.


1

La mia versione breve preferita di questo è

vnoremap s / y: s / "/

Quindi puoi evidenziare una selezione e premere semplicemente s / per avviare un comando di sostituzione per essa.


Non ha funzionato per me, trattato "come un letterale. <c-r>"ha funzionato però
Josh Bodah

1

Non ho il rappresentante per commentare, quindi aggiungo un'altra risposta ...

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

@dmd e @dotancohen: questo ha funzionato per me senza utilizzare up "h(usa esplicitamente 0, che è comunque l'ultima posizione di strappo) e funziona con putty ssh -> mint (lmde); non so di cent. Utilizza anche i commenti @Niloct e @Nathan Friend per rimuovere la conferma.


1

Esempio 1. Cita la selezione con le stelle, mantieni il cursore all'inizio della selezione.

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

Esempio 2. Metti in pipe il testo selezionato con base64:

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

Spiegazione LHS:

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

Spiegazione RHS:

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

0

Speravo ci fosse un modo integrato in Vim per sostituire una parola, senza dover riscrivere la parola in primo luogo. C'è, sebbene funzionerà solo per il testo fino a un carattere di confine di parola.

Dopo aver posizionato il mouse sulla parola, premere *o #per evidenziare la parola e passare alla posizione successiva / precedente di essa (se non si desidera modificare la posizione nel file, premere il tasto opposto per tornare alla posizione eri solo a).

Quindi digita semplicemente:

%s//<your-replacement-string>

Come accennato nella risposta di un'altra persona, se %sriceve una voce vuota tra le barre, utilizza la parola cercata in precedenza. Premendo *o #, stai cercando la parola sotto il cursore che la rende la parola cercata più di recente.

Alla fine sono solo sei o sette sequenze di tasti + lunghezza della parola sostitutiva per eseguire questa operazione e non richiede macro o modifica del tuo .vimrc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.