Cómo copiar cada línea 11 veces, incrementando el último "1" en cada línea de 2 a 12

9

Tengo varias líneas en un archivo, y me gustaría copiar cada línea 11 veces (convirtiendo cada línea en 12 líneas) e incrementar el último "1" en cada línea para que las 12 líneas tengan "1" a " 12 ", donde inicialmente estaba el" 1 ". Puede haber otras ocurrencias de "1" en cada línea, pero el "1" que deseo incrementar siempre será la última aparición en cada línea. Otra forma de verlo es que el último "1" siempre es después de "/ nt /", como en "/ nt / 1" (y siempre será la única aparición de "/ nt / 1" en cada línea) .

Entonces, por ejemplo, si tengo:

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Quiero convertirlo en:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
1stlineblahblahblah/nt/3blah
1stlineblahblahblah/nt/4blah
1stlineblahblahblah/nt/5blah
1stlineblahblahblah/nt/6blah
1stlineblahblahblah/nt/7blah
1stlineblahblahblah/nt/8blah
1stlineblahblahblah/nt/9blah
1stlineblahblahblah/nt/10blah
1stlineblahblahblah/nt/11blah
1stlineblahblahblah/nt/12blah
2ndlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah
...

Anteriormente había encontrado el comando:

:for i in range(0,12) | put ='1stlineblahblahblah/nt/'.i.'blah' | endfor

funciona para este propósito, pero tendría que ejecutar manualmente este comando para cada línea y escribir cada línea (o copiar y pegar) yo mismo. ¿Hay alguna manera de tomar las líneas que ya están en el archivo y simplemente ejecutar un comando que convierte cada línea en doce, de la manera que he descrito?

Gracias de antemano a cualquiera que pueda ayudarme con esto. También quería señalar que esta es mi segunda pregunta aquí, y me complació haber obtenido varias soluciones rápidas y efectivas a mi primera pregunta, por lo cual estaba muy agradecido.

ablewasiereisawelba
fuente

Respuestas:

8

Aquí hay una sustitución que resuelve el problema:

:%s/\(.*\)1\(.*\)/\=join(map(range(1, 12), 'submatch(1) . v:val . submatch(2)'), "\n")

La sustitución coincide con cada línea que contiene "1" y captura el texto antes {c1}y después {c2}del último "1". Para cada línea coincidente, el rango de números del uno al doce {n}se mapea para crear doce líneas del formulario {c1}{n}{c2}. Cada grupo de doce líneas reemplaza su línea asociada, originalmente emparejada.

Ver :h sub-replace-expression.

djjcast
fuente
2
Wow, gran comando de una línea. Recuerdo que también encontraste una solución elegante de una línea para la primera pregunta que hice hace unas semanas. Muy buen trabajo. Muchas gracias. Además, supongo que hay una manera de poner esto en el archivo _vimrc para que pueda ejecutar un comando o función fácil de recordar sin escribir toda la línea anterior (o tener que desplazarse por la lista de comandos anteriores), pero Todavía no estoy lo suficientemente familiarizado con la sintaxis _vimrc para saber cómo hacerlo.
ablewasiereisawelba
10

Podrías hacer esto por

  1. grabando una macro, entonces
  2. usando el globalcomando ex para ejecutar la macro n número de veces para cada línea en el archivo.

Después de grabar la macro, deshaga los cambios realizados durante la grabación, o habrá n + 1 líneas adicionales para la primera línea yn para líneas consecutivas.

Grabe la macro en el aregistro con

qayyp$?\d<CR><C-A>q

Esto registra en register a( qa...q) el siguiente comando:

  • yyp: duplicar la línea actual
  • $: mover al final de la línea
  • ?\d<CR>: busca hacia atrás un solo dígito
  • <C-A>: incrementa el dígito debajo del cursor en uno

Cuando se graba la macro, elimine los cambios realizados mientras la graba deshaciendo ( uu) o eliminando la línea actual ( dd). Luego repita la macro 11(o cualquier cantidad de) veces para cada línea en el archivo con el comando global:

:g//normal 11@a
jjaderberg
fuente
2
¡Funcionó! Muy bonito, gracias. Inicialmente tuve un problema con Ctrl-a resaltando todo en lugar de agregar, porque estoy usando gVim en Windows ... pero hice una búsqueda rápida y encontré este hilo - stackoverflow.com/questions/289681/… - donde utilicé la sugerencia de poner nnoremap <kPlus> <Ca> nnoremap <kMinus> <Cx> en _vimrc para poder usar las teclas "+" y "-" para sumar y restar. Además, el comando global tenía que ser: g // normal 11 @ a para mí, pero eso se resolvió fácilmente. ¡Gracias!
ablewasiereisawelba
6

Dos caminos:

¡Usa una macro!

Empezando con

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Con el cursor en la primera línea.

qqyyp$?\d<CR><Ctrl-a>q
10@q

Que hace:

qq Comience a grabar una macro en el registro q

yyp tira de la línea actual y pégala debajo

$?\d<CR> Ve al final de la línea y encuentra el primer dígito mirando hacia atrás

<Ctrl-a> Incrementar el número

q Deja de grabar la macro.

Esto te deja con:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah

Con el cursor en la segunda línea. Simplemente repita esta macro tantas veces como desee (por ejemplo, repítala diez veces con 10 @ q). Si desea automatizar este proceso para cada línea, ejecútelo globalmente en cada línea:

:g//normal 11@q

Alternativamente, con una versión más nueva de vim: pegue la línea que desee sin importar cuántas veces, bloque visual seleccione el dígito que desea incrementar y presione g <Ctrl-a>. Esto debería incrementar todos los números en el bloque visual como desee. Sin embargo, este es un proceso más manual.

fruglemonkey
fuente
1
Impresionante, no sabía sobre el g <c-a>camino. Gracias por compartir.
KBA está con Monica
1
@fruglemonkey La primera parte de su respuesta es la misma que la anterior, pero no obstante, gracias. La segunda parte, no creo que funcione para mí (a menos que esté haciendo algo mal), por lo que no debo estar usando la versión correcta.
ablewasiereisawelba
5

Me resulta más fácil usar macros para tareas de una sola vez como esa. Simplemente comience a grabar una macro con q+ nombre de registro y realice la tarea una vez. Veo una tarea repetible aquí:

  • Selecciona la linea
  • tirón
  • pegar (te pondrá en la siguiente línea)
  • ir al final de la línea
  • volver una palabra
  • incrementar en uno

Ahora grabe las pulsaciones de teclas necesarias para registrarse a, en modo normal:

qayyp$b<c-a>.

Elimine la línea nuevamente para probar si ejecutar la macro 11 veces produce el resultado correcto para una línea:

11@a

¡Lo hace! Así que vamos a deshacer nuevamente y automatizar todo el proceso en una segunda macro b:

qb11@aj

Ahora puede ejecutar @bhasta el final del archivo y debería producir la salida que desea. Suena complicado, pero en realidad no lo es una vez que estás acostumbrado a los patrones de edición típicos.

kba está con Monica
fuente
No estoy seguro de si estoy haciendo algo mal, pero parece que no funciona. Seguí lo que escribiste, pero tal vez no entendí algo o no ejecuté algo correctamente. (Estoy obteniendo el primer número de la línea incrementado, no el último número de la línea). Gracias por responder.
ablewasiereisawelba
3
Creo que la primera macro debería ser qaVyp$b<c-a>. O mejor, solo qayyp$b<c-a>.
Karl Yngve Lervåg
1
Gracias, @ KarlYngveLervåg, tienes razón, arreglé la macro.
kba está con Monica
2
Argh :( gracias por ser minucioso @ablewasiereisawelba. Supongo que la macro qqyyp$?\d<CR><Ctrl-a>qde @fruglemonkey y @jjaderberg es mejor ya que busca el último número. Lo cambiaré por completo.
kba está con Monica
2
@kba Solo pensé que si alguien se tomaba el tiempo y el esfuerzo para responder mi pregunta, al menos podría probar su solución, incluso si ya había encontrado una solución que funcionara de otra persona. Aprecio tu esfuerzo, y si te hace sentir mejor, todavía estás a millas de distancia. :)
ablewasiereisawelba
2

Guarde la siguiente macro y úsela para cada línea:

qqyy11p/\/\zs1<CR><C-v>10jg<C-a>q

La principal diferencia con respecto a las otras respuestas es que esto se utiliza g<C-a>en una selección de columna que incrementa cada línea con un número diferente. Consulte :help v_g_CTRL-Apara más información. También he usado \zspara seleccionar la posición de inicio del patrón, de modo que el cursor se detenga en el número después de la búsqueda.

Tenga en cuenta que necesita una versión reciente de Vim para que esto funcione.

Vitor
fuente
1
@fruglemonkey propuso eso también . Es una característica genial, aunque es bastante reciente (según los estándares vim), desde 7.4.754 que aún no se ha enviado a todas las distribuciones.
kba está con Monica
Lo perdimos lo siento
Vitor
1
@Vitor Solo tengo gVim 7.4, así que no creo que pueda hacer lo g<C-a>que @fruglemonkey y usted mencionó, pero gracias por responder. Debo tener en cuenta que al probar su macro, justo antes de llegar a la g<C-a>parte, no es el último carácter "1" que estoy buscando incrementar lo que se resalta en bloque, sino que es el carácter antes del primer "1" "personaje que se resalta en bloque. (Además, creo que habría sido así yy11py 10jen la macro, ya que estoy buscando agregar 11 líneas, para un total de 12.)
ablewasiereisawelba
1
Gracias por sus comentarios. He actualizado la respuesta en consecuencia. Decidí usarlo \zs, pero podría simplemente haber agregado un lafter <CR>.
Vitor
1
Probablemente tenga algunas configuraciones en su vimrc que afectan la búsqueda de expresiones regulares. Inténtalo de nuevo comenzando con Vim vim -u NONE. ¡Acabo de hacer eso y funciona perfectamente! De hecho, no hay forma de que la búsqueda coincida con el primer 1 porque requiere una barra inclinada anterior.
Vitor