Converti regex sed in regex vim

Sep 09 2020

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

2 D.BenKnoble Sep 10 2020 at 03:16

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.

3 Quasímodo Sep 10 2020 at 04:17
: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.

3 D.BenKnoble Sep 10 2020 at 06:31

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