Converter sed regex em vim regex
Eu tenho este sed regex que encontrei:
sed '/start/!d;s//&\n/;s/.*\n//;:a;/end/bb;$!{n;ba};:b;s//\n&/;P;D'
que basicamente produz o conteúdo que está entre um ponto inicial e um ponto final.
##1##
this is a test
with multiple
line
##z##
e substituindo startcom ##1##, e endpara ##z##daria:
this is a test
with multiple
line
Se houver várias ocorrências de ##1##e ##z##, então, obviamente, mostraria todo o texto intermediário dessa ocorrência, como:
##1##
this is a test
with multiple
line
##z##
##1##
this is a test
with multiple
line
##z##
para
this is a test
with multiple
line
this is a test
with multiple
line
Para esclarecer ainda mais:
##1##
this is a test
with multiple
line
##z##
##2##
test
##z##
obviamente forneceria apenas o que é especificado como ponto de partida (já que o ponto de término ##z##é sempre o mesmo). Então, se eu usar ##2##como ponto de partida:
test
Isso daria o resultado acima.
Meu objetivo é converter isso para um regex compatível para o vim. Estou usando este site e o manual local como ajuda, mas não tenho certeza por onde começar para converter o acima para vim regex.
Respostas
Uma função extremamente simples que faz o trabalho de maneira muito mais idiomática:
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
Nomeie como quiser e, em seguida, faça, por exemplo,
call Between('##1##', '##z##')
(que você poderia vincular a uma chave, talvez).
Para trabalhar no arquivo inteiro, você pode usar :global(ou apenas apenas :%call Between(...)), ou pode precisar de um loop envolvendo essa função e percorrendo o arquivo. No caso do último, eu usaria search(a:start)para encontrar o próximo início e então +estar dentro da região aninhada; então eu chamaria a função. Isso é mais rápido do que chamar a função em todas as linhas.
:g/END\|\%^/,/START\|\%$/s/.*//
Este comando global marca todas as linhas correspondentes ENDou o início do arquivo ( \%^). Em seguida, ele apaga tudo, desde as linhas marcadas até STARTo final do arquivo ( \%$) usando o comando de substituição s/.*//.
Um exemplo lado a lado:
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 você não quiser as linhas em branco, pode substituir s/.*//por dno comando global.
Apenas por diversão, lembre-se que você sempre pode fazer
:%!sed '/start/\!d;s//&\n/;s/.*\n//;:a;/end/bb;$\!{n;ba};:b;s//\n&/;P;D'
E isso ainda é “vim”: P