Come unire tutte le linee insieme quale modello di corrispondenza?


11

Vorrei unire le linee solo per le linee che hanno un certo modello (come ;), tuttavia quando lo si utilizza g/;/jnon funziona come previsto a meno che non venga chiamato un paio di volte.

Ad esempio il seguente contenuto:

a
1;
2;
3;
4;
5;
b
6;
7;
8;
9;
c

quando si utilizza: :g/;/jl'output è:

a
1; 2;
3; 4;
5; b
6; 7;
8; 9;
c

o :g/;/-jdà:

a 1; 2; 3; 4; 5;
b 6; 7; 8; 9;
c

simile con: :g/;\_.\{-};/j.

La mia uscita prevista è:

a 
1; 2; 3; 4; 5;
b
6; 7; 8; 9;
c

o qualcosa di simile, quindi tutte le linee contenenti il ​​modello sono unite.

Come si può ottenere questo?


3
FWIW, :g/;/jnon funziona perché viene eseguito in due passaggi: prima viene scansionato il buffer, quindi il comando viene applicato alle righe corrispondenti.
Romainl

Risposte:


12

Possibile spiegazione del problema

Penso che il motivo per cui :g/;/jnon funziona sia perché il :gcomando funziona con un algoritmo a 2 passaggi:

  • durante il primo passaggio segna le linee che contengono il motivo ;
  • durante il secondo passaggio opera sulle linee segnate

Durante il secondo passaggio, :gunisce la linea 1;con la linea 2;perché è 1;stata contrassegnata durante il primo passaggio. Tuttavia ho il sospetto (non sono sicuro) che non si unisce 1; 2;con 3;perché la linea 2;non esiste più, il suo contenuto è stata fusa con la linea 1;, che è già stato elaborato.

Quindi :gcerca la riga successiva che è stata contrassegnata durante il primo passaggio ( 3;) e si unisce a quella successiva ( 4;). Dopo di che le ripetizioni problema, non possono partecipare 3; 4;con 5;perché la linea 4;non esiste più.

Soluzione 1 (con vimscript)

Forse potresti chiamare una funzione ogni volta che ;viene trovata una riga contenente per verificare se la riga precedente contiene anche un punto e virgola:

function! JoinLines()
    if getline(line('.')-1) =~ ';'
        .-1join
    endif
endfunction

Quindi utilizzare il seguente comando globale:

:g/;/call JoinLines()

O senza una funzione:

:g/;/if getline(line('.')-1) =~ ';' | -j | endif

Soluzione 2 (senza vimscript)

:g/;/.,/^[^;]*$/-1j

Ogni volta che il comando globale :gtrova il modello ;esegue il comando: .,/^[^;]*$/-1j

Può essere suddiviso in questo modo:

:g/pattern/a,bj

Dove :

pattern = ;
a       = .           = number of current line
b       = /^[^;]*$/-1 = number of next line without any semicolon minus one

b può essere ulteriormente suddiviso in questo modo:

/    = look for the number of the next line matching the following pattern
^    = a beginning of line
[^;] = then any character except a semicolon
 *   = the last character can be repeated 0 or more times
 $   = an end of line
 /   = end of pattern
 -1  = removes one to the number you just got

jè la forma abbreviata del comando Ex :joinche come la maggior parte degli altri comandi Ex può essere preceduta da un intervallo.
Qui è preceduto dalla catena: .,/^[^;]*$/-1( a,b)
Una gamma segue la forma a,bdove ae bsono generalmente 2 numeri di riga, e permette di operare su un gruppo di linee cui numero è compreso tra ae b, invece di uno solo.

Quindi il jcomando unisce tutte le linee tra quella corrente ( a) e quella successiva che non contiene punti e virgola meno uno ( b).

Per ulteriori informazioni, vedere:

:help :global
:help :join
:help :range

1

Faccio in modo simile unendomi continuamente con una ricerca globale e sostituisco:

s /; \ n /; /

\n corrisponde a newline.

Per trovare ed eliminare le righe vuote:

s / ^ $ \ n //

Non sono sicuro del perché, ma se si desidera inserire una nuova riga è necessario utilizzare \r


sda solo funzionerà solo per una linea, per renderlo globale, devi usarlo %s, ma poi unirà quasi tutte le linee, comprese le non ;linee
kenorb

2
@kenorb Ehm no, penso che tu possa usare il :scomando esattamente per quello che vuoi. Penso che questo %s/;\n\(.*;\)\@=/;/faccia quello che ti serve.
Christian Brabandt,
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.