Converti regex sed in regex vim
Ho questa regex di sed che ho trovato:
sed '/start/!d;s//&\n/;s/.*\n//;:a;/end/bb;$!{n;ba};:b;s//\n&/;P;D'
che fondamentalmente produce il contenuto che si trova tra un punto iniziale e un punto finale.
##1##
this is a test
with multiple
line
##z##
e sostituendo startcon ##1##, e enda ##z##darebbe:
this is a test
with multiple
line
Se ci sono più occorrenze di ##1##e ##z##, allora ovviamente mostrerebbe tutto il testo intermedio di tale occorrenza, in questo modo:
##1##
this is a test
with multiple
line
##z##
##1##
this is a test
with multiple
line
##z##
per
this is a test
with multiple
line
this is a test
with multiple
line
Per chiarire ancora di più:
##1##
this is a test
with multiple
line
##z##
##2##
test
##z##
darebbe ovviamente solo ciò che è specificato come punto di partenza (poiché il punto finale ##z##è sempre lo stesso). Quindi se uso ##2##invece come punto di partenza:
test
Questo darebbe quanto sopra come output.
Il mio obiettivo è convertirlo in una regex compatibile per vim. Sto usando questo sito e il manuale locale come aiuto, ma non sono sicuro da dove iniziare per convertire quanto sopra in vim regex.
Risposte
Una funzione estremamente semplice che fa il lavoro in modo molto più idiomatico:
function! Between(start, end) abort
let [start_line, _] = searchpairpos(a:start, '', a:end, 'bWn')
let [end_line, _] = searchpairpos(a:start, '', a:end, 'Wn')
if start_line is# 0 || end_line is# 0
return
endif
call setline(start_line, '') " or: execute start_line 'delete'
call setline(end_line, '') " or: execute end_line 'delete'
endfunction
Assegnagli un nome come preferisci, quindi fai, ad esempio,
call Between('##1##', '##z##')
(che potresti associare a una chiave, forse).
Per lavorare sull'intero file, potresti essere in grado di utilizzare :global(o anche solo :%call Between(...)), oppure potresti aver bisogno di un ciclo che avvolge questa funzione e attraversa il file. Nel caso di quest'ultimo, userei search(a:start)per trovare l'inizio successivo e quindi +per essere all'interno della regione annidata; quindi chiamerei la funzione. È più veloce che chiamare la funzione su ogni riga.
:g/END\|\%^/,/START\|\%$/s/.*//
Questo comando globale contrassegna tutte le righe corrispondenti ENDo l'inizio di file ( \%^). Quindi procede con l'eliminazione di tutto, dalle righe contrassegnate fino alla STARTfine di file ( \%$) utilizzando il comando di sostituzione s/.*//.
Un esempio fianco a fianco:
Before |After
________________________________
test |
START |
this is a test |this is a test
with multiple |with multiple
line |line
END |
0 |
START |
0101 |0101
END |
11 |
111 |
Se non vuoi le righe vuote, puoi sostituirle s/.*//con dnel comando globale.
Solo per divertimento, ricorda che puoi sempre farlo
:%!sed '/start/\!d;s//&\n/;s/.*\n//;:a;/end/bb;$\!{n;ba};:b;s//\n&/;P;D'
E questo è ancora "vim": P