Come invertire ogni 4 righe?


13

Prima di tutto, essendo questo il mio primo post qui, vorrei solo dire che ho trovato VIM un ottimo strumento e che il forum qui è molto utile per trovare le risposte alle domande, con molte persone disponibili che forniscono assistenza inestimabile. Sono ancora molto nuovo in VIM, quindi praticamente tutto ciò che ho imparato a riguardo è venuto da qui.

La mia domanda è: so come invertire TUTTE le righe di un file (: g / ^ / m0 tra gli altri modi), ma c'è un modo per invertire ogni 4 righe di un file, in modo che

line1
line2
line3
line4
line5
line6
line7
line8
...

diventa

line4
line3
line2
line1
line8
line7
line6
line5
...

Si può presumere che ci sarà sempre un multiplo esatto di 4 righe in tali file.


2
Informazioni sulla tua "ps": se inserisci 4 spazi davanti a una riga, viene interpretato come codice (puoi selezionare il testo e usare i pulsanti di formattazione in alto). Puoi trovare maggiori dettagli sull'icona dell'interrogazione in alto .
lunedì

Risposte:


15

Il comando :Reversespiegato su Vim Wiki può essere usato per questo (puoi includerlo nel tuo .vimrcper renderlo permanente):

command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl

Quindi è possibile registrare una macro per eseguire il comando su ogni quattro righe:

qmV3j:Reverse<cr>4jq
1000@m

Spiegazione:

  • qm: 'q' in modalità normale avvia (e termina) la registrazione di una macro in un dato registro (registro 'm', in questo caso, ma potrebbe essere qualsiasi altra lettera)
  • V: entra in modalità visiva e seleziona la linea corrente
  • 3j: espande la selezione visiva alle 3 righe successive
  • :Reverse<cr>: esegui il comando Inverti sulle linee selezionate ( <cr>qui sta per il entertasto)
  • 4j: passa alle successive righe invariate
  • q: interrompe la registrazione della macro
  • 1000@m: esegui la macro registrata al registro 'm' 1000 volte (puoi aumentare questo numero se il tuo file è più grande di 4000 righe)

Modificare:

Come menzionato nei commenti, è possibile utilizzare una macro ricorsiva invece di utilizzare un conteggio:

qmV3j:Reverse<cr>4jq
qM@mq
@m
  • qM: se il registro specificato qè in maiuscolo, la macro viene aggiunta al registro (che è utile anche quando ti rendi conto quando hai perso gli ultimi passi su una macro complessa)
  • @m: esegue la macro sul registro m
  • q: interrompe l'aggiunta della macro

Nonostante sia stato creato come macro, puoi creare un comando per questo se è un'attività comune sul tuo flusso di lavoro:

function! Reverse4()
   let reg_m = @m
   let @m = '<c-r><c-r>m'
   normal! @m
   let @m = reg_m
endfunction
command! Reverse4 call Reverse4()
  • function! Reverse4()/ endfunction: definisce una nuova funzione
  • let reg_m = @m: salva il contenuto corrente del registro m
  • let @m = "<c-r><c-r>m": inserisci la macro nel registro m- nota che <c-r>è la notazione vim per Ctrl+ re che dovresti digitare questa, non copiare / incollare, quindi la tua linea sarà simile let @m = 'V3j:Reverse^M4j@m'e conterrà un carattere speciale (^ M)
  • normal! @m: il comando normale esegue il suo argomento come è stato digitato in modalità normale, quindi eseguirà la macro ricorsiva
  • let @m = reg_m: ripristina il contenuto del registro m, quindi non è necessario ricordare che questo registro viene utilizzato su questa funzione ed evitare di usarlo

  • command! Reverse4 call Reverse4(): crea un nuovo comando per questa funzione

A seconda delle esigenze, è possibile migliorarlo, ad esempio: passare un argomento al comando e alla funzione in modo che funzioni per qualsiasi numero di righe anziché essere risolto in gruppi di 4 righe.


Invece del 1000@qtrucco, è anche possibile utilizzare una macro ricorsiva: qmqqm ... @mq@m.
Doorknob,

Quando ho provato a eseguire il "qmV3j: Reverse <cr> 4jq", si diceva "E492: Not a editor editor". Devo fare qualcosa di sbagliato. A proposito, sto usando - e ho sempre usato - GVIM. Avrei dovuto dirlo in primo luogo.
ablewasiereisawelba,

Ah, non importa. L'ho capito - non dovrei digitare ":" prima della parte "qmV3j: Reverse <cr> 4jq". Ha funzionato! Grazie mille, mMontu. Se posso chiedere: come posso includere il comando ": Reverse" nel mio .vimrc?
ablewasiereisawelba,

3
@ablewasiereisawelba Per rendere il comando disponibile in modo permanente, basta scrivere la riga command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohlda qualche parte nel tuo VIMRC.
saginaw,

@saginaw Oh, non mi ero reso conto che fosse così semplice. Grazie.
ablewasiereisawelba,

9

Come per tutte le azioni ripetitive , se puoi fare qualcosa una volta con le operazioni di modifica di base, puoi farlo facilmente molte volte registrando una macro.

(In questo caso userò una macro ricorsiva, ma potresti semplicemente registrarne una non ricorsiva e riprodurla più volte martellando @@o usando un conteggio.)

ggqqqqqddjjpkddkkPjddpjj@qq@q

Suddiviso

  1. gg: Passa all'inizio del file.
  2. qqq: Cancella registro q. Vedremo perché questo è necessario nel passaggio 5.
  3. qq: Avvia la registrazione di una macro per registrare q
  4. ddjjpkddkkPjddpjj: Una serie di operazioni che riordina le prime quattro righe semplicemente eliminandole e incollandole manualmente. (Questo potrebbe sembrare complicato a prima vista, ma non lasciatevi ingannare Questa è roba molto di base che avresti imparato nei primi 5 minuti o giù di lì. vimtutor: j, k, dd, p, P)
  5. @q: Chiama la macro! A questo punto, register qnon contiene nulla (perché l'abbiamo eliminato nel passaggio 2), quindi non accadrà nulla.
  6. q: Interrompe la registrazione della macro.
  7. @q: Riprodurre la macro ricorsiva tutte le volte che è necessario.

NB Quanto sopra non produrrà i risultati desiderati se il file contiene un numero di righe che non è esattamente divisibile per quattro. Per interrompere la macro in anticipo se non sono rimaste quattro righe, è necessario eseguire un comando Vim in modalità normale che non riuscirà, prima di iniziare ad applicare le modifiche al passaggio 4. Possiamo farlo tentando di spostarci verso il basso una linea tre volte (e poi il backup) prima di iniziare a spostare le linee in giro:jjj3k

Così:

ggqqqqqjjj3kddjjpkddkkPjddpjj@qq@q

Perché si cancella esplicitamente il registro q? Se ti registri, tutto ciò che era lì verrà comunque sovrascritto ....
Wildcard

4
@Wildcard Perché è una macro ricorsiva, la prima volta che chiami il contenuto di register q, deve essere vuota, altrimenti rovinerà le tue edizioni.
saginaw,

Molto bella. Ho provato questo in modo interattivo senza provare a digitare l'esatta sequenza del tuo comando e ho finito usando:qqqggqqjjjkddkkPjddjpkddkkPjjjj@qq@q
Wildcard

1
@ablewasiereisawelba where I can just use the one-line custom command each time I need to do this- nota che non è necessario ricreare la macro ogni volta che è necessario utilizzarla, poiché è possibile memorizzarla come funzione / comando sul proprio vimrc.
lunedì

1
@ablewasiereisawelba Sono contento che tu abbia trovato utile "Modifica"! Dato che questo è stato il tuo primo post qui forse non sei a conoscenza di come funzionano le notifiche StackExchange: quando pubblichi un commento, l'autore della risposta / domande riceve una notifica; altre persone riceveranno una notifica solo se includi @ <nick>. Quindi solo Rich ha ricevuto notifiche sui tuoi ultimi messaggi.
lunedì

7

Puoi anche farlo con un Excomando usando sedcome filtro esterno:

:%!sed -n 'h;n;G;h;n;G;h;n;G;p'

Questa versione ignorerà (eliminerà) tutte le righe extra oltre un multiplo di 4. Per mantenere nell'ultima serie di meno di 4 righe (invertite), utilizzare:

:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'

Il %qui significa "Ogni riga nel buffer".

Il !comando significa "Esegui il seguente comando con le righe specificate come input e sostituisci le righe specificate con l'output del comando". (Si chiama filtro; molto utile per cose come l'ordinamento, ad esempio, :%!sortordinerà tutte le linee nel tuo file; :2,8!sortordinerà le linee 2-8, ecc.)

sedè lo strumento dell'editor di stream e si trova su tutti i sistemi simili a Unix. I concetti chiave sedusati qui sono lo "spazio modello" (che per impostazione predefinita contiene a sua volta ciascuna riga dell'input) e lo "spazio trattenuto" (che è il punto in cui è possibile incollare del testo extra mentre lo si utilizza sedper salvarlo mentre si elaborano altri linee di input).

-nè un'opzione al sedcomando per sopprimere le sue azioni predefinite di stampa dello spazio modello (perché in questo caso vogliamo stampare solo quando lo diciamo esplicitamente).

$pnel sedcomando significa "Se ti trovi nell'ultima riga seddell'input, stampa (lo spazio del motivo)."

h significa "attaccare il contenuto corrente dello" spazio modello "nello" spazio di attesa ", sovrascrivendo qualsiasi cosa ci sia".

n significa "sostituisci il contenuto dello" spazio modello "con la riga successiva dall'input."

G significa "aggiungi allo" spazio modello ": una nuova riga seguita dal contenuto dello" spazio di attesa "."

Presi tutti insieme, il sedcomando memorizza quattro righe di output, invertendole mentre le memorizza e quindi le stampa. I $pcomandi aggiunti nella seconda versione assicurano che se viene raggiunta l'ultima riga del file se non su un multiplo di 4 righe, le linee vengono comunque stampate.


Per un approccio alternativo e interattivo, ancora senza l'utilizzo di funzionalità specifiche di Vim e anche senza l'utilizzo di un filtro esterno:

:4

per andare alla quarta riga.

:.m -4 | +3m . | +2m . | +5

per invertire le quattro righe precedenti (1-4) e lasciare il cursore sulla riga 8.

.m -4sposta la riga corrente subito dopo la riga di quattro righe indietro (lasciando il cursore sulla riga spostata).

+3m .sposta la linea che è 3 linee dopo la linea corrente, subito dopo la linea corrente, lasciando il cursore sulla linea spostata. +2m .ovviamente funziona allo stesso modo.

+5 posiziona il cursore a cinque righe dal punto in cui si trova.

Ripeti come desiderato.

In Vim puoi ripetere l'intero comando con @:, quindi ripetere di nuovo con @@. In POSIX vio exdovresti inserire :.m -4 | +3m . | +2m . | +5 una riga di testo, eliminarlo in un buffer con nome (registro), quindi eseguire quel buffer con nome (registro).

Pertanto, in exmodalità, invertendo le righe in modo interattivo utilizzando solo le funzionalità specificate da POSIX e iniziando con 17 righe di testo:

Entering Ex mode.  Type "visual" to go to Normal mode.
:0a     # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
.       # End text insertion
:d k    # Delete that line to register k
line1   # This is a printout of the current line
:4      # Move to line 4
line4
:@k     # Execute register k to reverse lines 1-4
line8
:@@     # Execute register k again
line12
:@@     # Execute register k again
line16
:@@     # Execute register k again
line17
:%p     # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq     # Save and quit

Ulteriori letture:


Potresti spiegare un po 'di più la tua soluzione?
vappolinario,

3
@vappolinario, ho aggiunto qualche ulteriore spiegazione. Questo aiuta? :)
Wildcard

Caspita, risposta molto lunga. :) In realtà ho sed, ma l'ho appena usato con un semplice script che ho trovato da qualche parte - probabilmente su questa scheda - che era una soluzione a un problema che avevo. Tuttavia, quando ho provato a eseguire la riga suggerita, si dice che "'sed' non viene riconosciuto come comando interno o esterno, programma eseguibile o file batch." Non sono sicuro se ho bisogno di avere sed nella cartella vim o cosa.
ablewasiereisawelba il

1
@ablewasiereisawelba, se si esegue su una finestra di Windows e non si utilizza Cygwin (o MobaXterm o simile), è possibile provare l'altro metodo che ho dato: 4G:.m -4 | +3m . | +2m . | +5<Enter>@:quindi @@ripetuto fino a quando il file non è completamente elaborato. Consiglio comunque di installare MobaXterm. :)
Wildcard

@Wildcard Oh okay, sto provando MobaXterm ora. :)
ablewasiereisawelba,

7
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')

Inglese semplice: per ogni riga, sposta la riga corrente verso l'alto lnum % 4, a meno che lnum % 4 == 0, nel qual caso, sposta la riga corrente verso l'alto 4.

Inoltre, per invertire tutte le nrighe, sostituisci le 4'nel comando sopra con n.


2
Comando a una riga molto bello. Grazie, djjcast.
ablewasiereisawelba il
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.