Converter sed regex em vim regex

Sep 09 2020

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

2 D.BenKnoble Sep 10 2020 at 03:16

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.

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

3 D.BenKnoble Sep 10 2020 at 06:31

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