Come copiare ogni riga 11 volte, incrementando l'ultimo “1” in ogni riga da 2-12


9

Ho un numero di righe in un file e vorrei copiare ogni riga 11 volte (trasformando ogni riga in 12 righe) e incrementare l'ultimo "1" in ogni riga in modo che le 12 righe abbiano "1" attraverso " 12 ", dove inizialmente era" 1 ". Potrebbero esserci altre occorrenze di "1" in ciascuna riga, ma "1" che voglio incrementare sarà sempre l'ultima occorrenza in ciascuna riga. Un altro modo di vederlo è che l'ultimo "1" è sempre dopo "/ nt /" - come in "/ nt / 1" (e sarà sempre l'unica occorrenza di "/ nt / 1" in ogni riga) .

Quindi, ad esempio, se ho:

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

Voglio trasformarlo in:

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

In precedenza avevo trovato il comando:

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

funziona a questo scopo, ma dovrei eseguire manualmente questo comando per ogni riga e digitare ogni riga (o copiarlo e incollarlo) da solo. C'è un modo per prendere le linee che sono già nel file ed eseguire solo un comando che trasforma ogni linea in dodici, nel modo che ho descritto?

Grazie in anticipo a chiunque mi possa aiutare in questo. Volevo anche notare che questa è la mia seconda domanda qui, e sono stato contento di aver ottenuto diverse soluzioni rapide ed efficaci alla mia prima domanda, di cui sono stato molto grato.

Risposte:


8

Ecco una sostituzione che risolve il problema:

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

La sostituzione corrisponde a ciascuna riga che contiene "1" e acquisisce il testo prima {c1}e dopo {c2}l'ultimo "1". Per ogni linea abbinata, l'intervallo di numeri da uno a dodici {n}viene mappato per creare dodici linee del modulo {c1}{n}{c2}. Ogni gruppo di dodici righe sostituisce la relativa linea associata originariamente.

Vedere :h sub-replace-expression.


2
Wow, ottimo comando su una riga. Ricordo che hai anche trovato un'elegante soluzione a una riga per la prima domanda che ho posto qualche settimana fa. Ottimo lavoro Grazie mille. Inoltre, immagino che ci sia un modo per inserirlo nel file _vimrc in modo da poter eseguire un comando o una funzione facile da ricordare senza digitare l'intera riga sopra (o dover scorrere l'elenco dei comandi precedenti), ma Non ho ancora abbastanza familiarità con la sintassi _vimrc per sapere come farlo.
ablewasiereisawelba,

10

Potresti farlo entro

  1. registrando una macro, quindi
  2. usando il globalcomando ex per eseguire la macro n numero di volte per ogni riga nel file.

Dopo aver registrato la macro, annulla le modifiche apportate durante la registrazione, altrimenti ci saranno n + 1 righe aggiuntive per la prima riga e n per righe consecutive.

Registra la macro nel aregistro con

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

Questo registra in register a( qa...q) il seguente comando:

  • yyp: duplica la riga corrente
  • $: passa alla fine della riga
  • ?\d<CR>: cerca all'indietro una singola cifra
  • <C-A>: incrementa la cifra sotto il cursore di una

Quando la macro viene registrata, rimuovere le modifiche apportate durante la registrazione annullando ( uu) o eliminando la riga corrente ( dd). Quindi ripetere la macro 11(o qualsiasi numero di) volte per ciascuna riga del file con il comando globale:

:g//normal 11@a

2
Ha funzionato! Molto bello grazie. Inizialmente ho avuto un problema con il Ctrl-a evidenziando tutto invece di aggiungere, perché sto usando gVim in Windows ... ma ho fatto una ricerca veloce e ho trovato questo thread - stackoverflow.com/questions/289681/… - dove ho usato il suggerimento di mettere nnoremap <kPlus> <Ca> nnoremap <kMinus> <Cx> in _vimrc in modo che io possa usare i tasti "+" e "-" per aggiungere e sottrarre. Inoltre, il comando globale doveva essere: g // normal 11 @ a per me, ma è stato facilmente capito. Grazie!
ablewasiereisawelba,

6

Due strade:

Usa una macro!

Iniziare con

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

Con il cursore sulla prima riga

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

Che fa:

qq Inizia a registrare una macro nel registro q

yyp strappare la linea corrente e incollarla di seguito

$?\d<CR> Vai alla fine della riga e trova la prima cifra che guarda indietro

<Ctrl-a> Incrementa il numero

q Interrompere la registrazione della macro.

Questo ti lascia con:

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

Con il cursore sulla seconda riga. Basta ripetere questa macro tutte le volte che lo si desidera (ad esempio, ripeterlo dieci volte con 10 @ q). Se si desidera automatizzare questo processo per ogni riga, eseguirlo globalmente su ogni riga:

:g//normal 11@q

In alternativa, con una versione più recente di vim: incolla la linea desiderata per molte volte, blocco visivo seleziona la cifra che desideri incrementare e premi g <Ctrl-a>. Questo dovrebbe incrementare tutti i numeri nel blocco visivo come desideri. Questo è un processo più manuale, tuttavia.


1
Fantastico, non sapevo g <c-a>come. Grazie per la condivisione.
Kba sta con Monica il

1
@fruglemonkey La prima parte della tua risposta è la stessa di quella sopra, ma comunque grazie. La seconda parte, non credo funzioni per me (a meno che non stia facendo qualcosa di sbagliato), quindi non devo usare la versione giusta.
ablewasiereisawelba,

5

Trovo più facile usare le macro per attività come questa. Basta iniziare a registrare una macro con q+ nome del registro ed eseguire l'attività una volta. Vedo un compito ripetibile qui:

  • Seleziona la linea
  • strattone
  • incolla (ti inserirà nella riga successiva)
  • vai alla fine della linea
  • torna indietro di una parola
  • incrementare di uno

Ora registra le sequenze di tasti richieste per registrarti a, in modalità normale:

qayyp$b<c-a>.

Elimina di nuovo la riga per verificare se l'esecuzione della macro 11 volte produce il risultato giusto per una riga:

11@a

Lo fa! Quindi annulla di nuovo e automatizza l'intero processo in una seconda macro b:

qb11@aj

Ora puoi eseguire @bfino alla fine del file e dovrebbe produrre l'output desiderato. Sembra complicato ma in realtà non lo è una volta che sei abituato ai tipici schemi di modifica.


Non sono sicuro che stia facendo qualcosa di sbagliato, ma non sembra funzionare. Ho seguito quello che hai scritto, ma forse ho frainteso qualcosa o non ho eseguito correttamente qualcosa. (Ottengo il primo numero della riga incrementato, non l'ultimo numero della riga.) Grazie per la risposta.
ablewasiereisawelba,

3
Penso che la prima macro dovrebbe essere qaVyp$b<c-a>. O meglio, solo qayyp$b<c-a>.
Karl Yngve Lervåg,

1
Grazie, @ KarlYngveLervåg, hai ragione, ho corretto la macro.
Kba sta con Monica il

2
Argh :( grazie per essere accurato @ablewasiereisawelba. Immagino che la macro qqyyp$?\d<CR><Ctrl-a>qdi @fruglemonkey e @jjaderberg sia migliore poiché cerca l'ultimo numero. La cambierò per completezza.
Kba sta con Monica il

2
@kba Ho pensato che se qualcuno si prendesse il tempo e gli sforzi per rispondere alla mia domanda, avrei potuto almeno provare la sua soluzione, anche se avessi già trovato una soluzione funzionante da qualcun altro. Apprezzo il tuo sforzo - e se ti fa sentire meglio, sei ancora miglia davanti a me. :)
ablewasiereisawelba,

2

Salvare la seguente macro e utilizzarla per ogni riga:

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

La differenza principale rispetto alle altre risposte è che questo fa uso di g<C-a>una selezione di colonne che incrementa ogni riga con un numero diverso. Controlla :help v_g_CTRL-Aper maggiori informazioni. Ho anche usato \zsper selezionare la posizione iniziale del modello, in modo tale che il cursore si fermi sul numero dopo la ricerca.

Si noti che è necessaria una versione recente di Vim affinché funzioni.


1
Anche @fruglemonkey lo ha proposto . È una funzionalità interessante, anche se è abbastanza recente (secondo gli standard di VIM), dal 7.4.754 che non è ancora stato spedito a tutte le distribuzioni.
Kba sta con Monica il

Mi è mancato scusa
Vitor

1
@Vitor Ho appena gVim 7.4, quindi non credo di poter fare g<C-a>quel @fruglemonkey e tu mi hai fatto riferimento, ma grazie per aver risposto. Dovrei notare che quando provo la tua macro - poco prima di arrivare alla g<C-a>parte, non è l'ultimo carattere "1" che sto cercando di incrementare che viene evidenziato in blocco, ma invece è il personaggio prima del primo "1 "personaggio che viene evidenziato in blocco. (Inoltre, penso che sarebbe stato yy11pe 10jnella macro, poiché sto cercando di aggiungere 11 righe - per un totale di 12.)
ablewasiereisawelba

1
Grazie per il tuo feedback Ho aggiornato la risposta di conseguenza. \zsHo deciso di utilizzare , ma avrei potuto semplicemente aggiungere un ldopo <CR>.
Vitor

1
Probabilmente hai alcune impostazioni nel tuo vimrc che influenzano la ricerca di espressioni regolari. Riprovare avviando Vim con vim -u NONE. L'ho appena fatto e questo funziona perfettamente! In effetti, non è possibile che la ricerca corrisponda al primo 1 perché richiede una barra precedente.
Vitor,
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.