Vim busca y reemplaza el texto seleccionado

109

Digamos que tenemos un texto, y entro en modo visual y selecciono un texto. ¿Cómo hago una búsqueda rápida del texto resaltado y lo reemplazo con otra cosa?

Gabriel Solomon
fuente

Respuestas:

135

Intente ejecutar lo siguiente o ponerlo en su .vimrc

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

Al presionar ctrl+ ren el modo visual, se le pedirá que ingrese el texto para reemplazarlo. Presione entery luego confirme cada cambio con el que esté de acuerdo yo rechace n.

Este comando anulará su registro hpara que pueda elegir otro (cambiando hel comando anterior a otra letra minúscula) que no utilice.

Mykola Golubyev
fuente
13
Si se omite el cen gc, sustituya a la vez que se hace en todo el búfer. Si cometió un error y desea revertirlo, simplemente escriba uen modo comando. Me gusta más este enfoque que confirmar cada uno de los reemplazos (eso sucede con el cmodificador).
Niloct
3
vmap * y:let @/ = @"<CR>seleccionado está resaltado.
kev
8
¿Cuál es el objetivo de <left><left><left>?
aymericbeaumet
7
@aymericbeaumet para colocar el cursor entre las dos barras diagonales, de esa manera la palabra de reemplazo se puede escribir fácilmente.
mcabrams
5
Tenga en cuenta que si acepta la sugerencia de @ Niloct sobre eliminar el cde gc, también tendrá que eliminar uno de los <left>del final de la línea.
Nathan Friend
36

Esta búsqueda de mapeo rápida y simple para texto resaltado visualmente (sin sobrescribir el registro h) y sin usar el registro + dependiente del terminal:

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

Si no le gusta ctrl-f cámbielo a su preferencia

Una vez que el texto está resaltado, siempre puede hacer una ssustitución simplemente escribiendo:

%s//<your-replacement-string>

... porque una búsqueda en blanco en el scomando usa la última cadena buscada.

ErichBSchulz
fuente
Cuando uso esto en mi configuración de vim, control+fsiempre selecciono el siguiente carácter, así como lo que seleccioné visualmente. ¿Algunas ideas?
Robert Mark Bram
%s//<your-replacement-string>no parece funcionar para resaltar algo como /tmp/file. simplemente se convierte en<your-replacement-string>/tmp/file
naisanza
28

Este también funciona (al menos para selecciones en una sola línea / selecciones que no contienen ningún carácter especial)

  • seleccionar el texto en modo visual
  • tira del texto con y
  • :s/<C-r>0/

0 es el registro de yank.

Como mencionaron otras personas, hay formas más rápidas de hacer esto, pero si acaba de empezar a aprender Vim (como yo), esta es una de las formas "genéricas".

// editar: Me acabo de dar cuenta de que el enfoque de 'registro' fallará si hay caracteres como pestañas o nuevas líneas o /caracteres en la selección (tendría que procesar manualmente esos caracteres de alguna manera para que el :scomando funcione):

ingrese la descripción de la imagen aquí

colemik
fuente
2
Es muy simple. Oh Dios, por qué no está cubierto en la wiki. Vamos ... ¡Gracias por la respuesta!
Benyamin Limanto
2
Esta es la respuesta ideal para aquellos de nosotros que todavía estamos en la primera parte de la curva de aprendizaje de Vim. Sé que la personalización es una fortaleza, pero no quiero copiar y pegar un script complejo en mi vimrc y descifrar cómo encaja para un problema tan simple como este. Esta respuesta me enseñó que ctrl-R vuelca un registro, que será útil para recordar en otros contextos.
nivek
26

La respuesta aceptada funciona muy bien a menos que tenga caracteres especiales en su selección visual. Hackeé dos scripts (el de Jeremy Cantrell publicado aquí y el de Peter Odding ) para crear un comando que le permitirá seleccionar visualmente una cadena que desee encontrar incluso si tiene caracteres especiales de expresión regular.

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

He incluido esto en mi vimrc si es más útil para alguien.

bryan kennedy
fuente
2
gracias por la solución, combinando múltiples propuestas, terminé con lo siguiente: vmap <C-r> <Esc>:%s/<c-r>=GetVisual()<cr>//g<left><left>(que simplemente reemplaza todo en el archivo)
Peter Butkovic
13

Desde Vim 7.4, puede usar el gnmovimiento que selecciona regiones de texto que coinciden con el patrón de búsqueda actual.

Después de usar cgnpara cambiar el texto en la coincidencia seleccionada actualmente (o dgnpara eliminar), en el modo normal, puede usar .para repetir el comando y operar en la siguiente coincidencia.

Hay un episodio de Vimcast que muestra esta función.

Dapeng Li
fuente
3
¡Esta es una respuesta genial!
mauriciojost
Esto también es asombroso. aparte de la respuesta de colemik. ¡Muy buena!
Benyamin Limanto
guau, es como uno de esos secretos que encuentras cuando navegas profundamente para encontrar una buena solución, ¡gracias!
vdegenne
8

Mykola Golubyev, ¡Gracias por la sugerencia! A continuación se usa el registro "+" que (dependiendo de su terminal) ya contiene el texto resaltado, ahorrándose el uso del registro "h".

vnoremap <C-r> <Esc>:%s/<C-r>+//gc<left><left><left>
dmd
fuente
Mi VIM 7.0 en CentOS 5.x no parece tener el registro +. ¿Es esta una característica estándar?
dotancohen
3
Observo que accedo a la máquina CentOS a través de Putty, y al buscar en Google veo que + es el registro del portapapeles. ¡Putty no parece apoyar eso! Entonces, esta respuesta depende de la terminal.
dotancohen
Hola, probé su comando pero me pide que reemplace las ocurrencias del texto especificado en todo el archivo, y no solo el texto seleccionado
solalito
7

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

Cuando el texto esté seleccionado visualmente, presione: para ingresar un comando. La línea de comando ingresará automáticamente al rango:

:'<,'>

Puede ingresar un comando como s / red / green / g para reemplazar cada rojo con verde en todas las líneas de la última selección visual. El comando aparecerá como:

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

Para repetir un comando Ex sobre un bloque previamente seleccionado, use el: historial. Es decir, presione: luego, luego edite un comando anterior.

syvex
fuente
4
sí, esto reemplaza el rojo con verde en el área seleccionada , muy útil, pero no es lo que pidió la operación.
ErichBSchulz
@ErichBSchulz Realmente lo hace en todas las líneas seleccionadas. Entonces, incluso si solo se selecciona parte de una línea, lo hará en toda la línea.
Cully
1
Quizás no responda a la pregunta de OP, pero esto responde exactamente a mi búsqueda "vim buscar y reemplazar con selección visual", donde quiero limitar la búsqueda y reemplazar solo a la selección visual, lo que plantea esta pregunta
icc97
5

Tengo esto en mi 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>/

Esto tomará la selección visual e iniciará un comando de sustitución con ella.

EDITAR: Debo señalar que esto no funciona con selecciones visuales multilínea. Si bien GetVisual () no tiene problemas para devolverlo, no estoy seguro de cómo colocarlo correctamente en la línea de comandos. Si alguien tiene algún consejo sobre cómo podría hacer esto, por favor comente.

Jeremy Cantrell
fuente
2

No creo que puedas hacer esto de inmediato. Pero a mucha gente le gusta esta función, así que hay toneladas de macros y cosas así (yo mismo la agregué). Aquí hay uno que puede agregar, por ejemplo; simplemente presione *para buscar la siguiente coincidencia en el texto seleccionado visualmente.

John Feminella
fuente
2

Otras respuestas son buenas pero no escapan a los caracteres especiales. La respuesta de @brian kennedy muestra un método para escapar pero requiere mucho código. En el caso de una URL, por ejemplo, el escape es obligatorio o la búsqueda se detendrá en ":".

Como está escrito en vim.fandom.com/wiki/Search_for_visually_selected_text , puedes hacer un delineador para buscar y escapar algunos caracteres. Puedes escapar de los personajes que quieras, yo elegí escapar /\: :

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

Con este mapa, debo presionar //en modo visual para buscar el texto seleccionado actualmente en todo el búfer.

RomainTT
fuente
1

Mi versión corta favorita de esto es

vnoremap s / y: s / "/

Luego puede resaltar una selección y simplemente presionar s / para iniciar un comando de sustitución para ella.

alex
fuente
No funcionó para mí, tratado "como literal. <c-r>"aunque funcionó
Josh Bodah
1

No tengo el representante para comentar, así que estoy agregando otra respuesta ...

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

@dmd y @dotancohen: esto funcionó para mí sin consumir "h(usa explícitamente 0, que es la última posición de tirón de todos modos) y funciona con putty ssh -> mint (lmde); no sé sobre ciento. También utiliza los comentarios de @Niloct y @Nathan Friend para eliminar la confirmación.

10'004
fuente
1

Ejemplo 1. Citar la selección con estrellas, mantener el cursor al inicio de la selección.

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

Ejemplo 2. Canalice el texto seleccionado con base64:

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

Explicación LHS:

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

Explicación RHS:

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

Tenía la esperanza de que hubiera una forma incorporada en Vim para reemplazar una palabra, sin tener que volver a escribir la palabra en primer lugar. La hay, aunque solo funcionará para texto hasta un carácter de límite de palabra.

Una vez que haya pasado el mouse sobre la palabra, presione *o #para resaltar la palabra y salte a la ubicación anterior / siguiente de la misma (si no desea cambiar las ubicaciones en el archivo, presione la tecla opuesta para volver a la ubicación estabas en).

Entonces simplemente escriba:

%s//<your-replacement-string>

Como se menciona en la respuesta de otra persona, si %srecibe una entrada en blanco entre las barras, entonces usa la palabra buscada anteriormente. Al presionar *o #, está buscando la palabra debajo del cursor que la convierte en la palabra buscada más recientemente.

Al final, son solo seis o siete pulsaciones de teclas + la longitud de la palabra de reemplazo para realizar esto y no requiere macro ni edición de su .vimrc.

Cameron Gagnon
fuente