Vim: s reemplaza las primeras ocurrencias N <g en una línea


13

En vim, a veces tengo la oportunidad de reemplazar las primeras apariciones de un partido en una línea, pero no todas las que quisiera lo gharían. p.ej:

a a a a a

a

b b b a a

Sé que podría usar :s/a/b/[enter]:[up][enter]:[up][enter], pero eso es bastante tedioso en tres repeticiones, tengo líneas con potencialmente más de 10 sustituciones.
He intentado:

  • :s/a/b/3g: vim se quejó de los caracteres finales.
  • :s/a/b/3: cambia la primera aparición en esta y las siguientes dos líneas.
  • 3:s/a/b: Igual que el anterior.
  • :s/a/b/g3: cambia todas las apariciones en esta y las dos líneas siguientes.
  • :3s/a/b: cambia la primera aparición en la línea 3.
  • :/a/,3/a/s/a/b: cambia la primera aparición en cada línea entre la siguiente ay la tercera línea que contiene ael archivo (solicitando revertir si es necesario).
  • :/a/,/\([^a]*a\)\{3\}/s/a/b/: cambia la primera aparición en cada línea entre esta y la siguiente con 3 as (y esto no habría sido fácilmente extensible a una búsqueda de varios caracteres).

Y varios otros patrones de direccionamiento, ninguno de los cuales funcionó. Debo decir que he aprendido bastante sobre el :scomando que intenta encontrar una respuesta a este problema, pero aún no lo he resuelto.

Alguien sabe cómo hacer esto?

(puntos de bonificación para un rango específico, por ejemplo, del segundo al cuarto caso)


2
Estoy bastante seguro de que no puede hacer eso en vim, pero para hacerlo menos tedioso, ¿sabe acerca de "n" y "". en modo visual? Es decir, usa / patrón / para encontrar la cosa a cambiar, cámbiela usando "cw" o lo que sea, luego use "n" (solo n, sin comillas) para encontrar el siguiente patrón y presione "." (solo punto, sin comillas) para realizar la última edición.
Bruce Ediger

@BruceEdiger que conocía ny ., aunque no pensé en usarlos aquí. Sin duda una mejora, gracias.
Kevin

s/a/=something/debería hacer el truco ( :help sub-replace-=). No soy lo suficientemente fluido en Vim para escribir de somethinginmediato.
Gilles 'SO- deja de ser malvado'

Nota: :[up][enter]se puede reemplazar con &, lo que aún no es ideal, pero al menos es menos doloroso.
Kowh

Respuestas:


10

Sobre la base de la :s/pattern/replacement/gc idea de Samus_ (que parece ser la forma más sencilla de garantizar un funcionamiento correcto cuando el patrón está contenido dentro de la cadena de reemplazo), para reemplazar las ocurrencias segunda a cuarta en una sola línea:

:call feedkeys("nyyyq") | s/pat/string/gc

feedkeys()es una función que introduce la cadena de entrada en la cola de entrada del teclado. El punto es hacer el conteo por adelantado para que no tenga que preocuparse por perder el conteo o ser interrumpido.

Para un caso más general, para reemplazar las ocurrencias de Mth a Nth en una sola línea para N mayor o igual que una M muy grande :

:call feedkeys(repeat("n", M-1) . repeat("y", N-M+1) . "q") | s/pat/string/gc

Reemplace M y N con los valores que desee (incluso puede dejar vimhacer la aritmética mental trivial si no quiere hacerlo usted mismo). Tenga en cuenta que .es el operador de concatenación de cadenas de VimL. Obviamente, esto solo ahorra pulsaciones de teclas para M grandes . Si usa esta funcionalidad con frecuencia, puede ahorrarle tiempo colocar lo anterior en un comando o función personalizada de algún tipo, ya que es bastante difícil de escribir.


Hmm Me gusta este. También debería poder escribir una función para ello.
Kevin

8

Para la primera pregunta que haría:

:s/a/b
&&

El segundo es más complicado, no sé cómo hacerlo automáticamente, pero puedes hacer que vim te pregunte en cada partida de esta manera:

:s/a/b/gc

Luego responde "no" a las primeras n coincidencias y "sí" a las demás.


Hmm, me olvidé c, esa podría ser la mejor solución propuesta hasta ahora. Todavía tendría que contar, pero creo que es la primera opción que funcionaría con reemplazos que contienen la cadena de búsqueda.
Kevin

6
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a

:3,6g/^/let i=0 | while i<3 | s/a/b/ | let i+=1 | endwhile

a a a a a
a a a a a
b b b a a
b b b a a
b b b a a
b b b a a
a a a a a

1
Esto es bueno, pero aún sufre el problema que Gilles señaló (en otra publicación, que parece haberse eliminado), que solo funciona si el reemplazo no contiene el patrón. Aunque me gusta la idea de los scripts.
Kevin

¡Una cosa de belleza!
obispo

1

Creo que esto podría funcionar, reemplazar primero, luego repetir 2 veces:

:s/a/b/
2@:
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.