Convierta sed regex en vim regex
Tengo esta expresión regular sed que encontré:
sed '/start/!d;s//&\n/;s/.*\n//;:a;/end/bb;$!{n;ba};:b;s//\n&/;P;D'
que básicamente genera el contenido que se encuentra entre un punto de partida y un punto final.
##1##
this is a test
with multiple
line
##z##
y la sustitución startcon ##1##, y enda ##z##daría:
this is a test
with multiple
line
Si hay múltiples apariciones de ##1##y ##z##, entonces obviamente mostraría todo el texto intermedio de dicha ocurrencia, así:
##1##
this is a test
with multiple
line
##z##
##1##
this is a test
with multiple
line
##z##
a
this is a test
with multiple
line
this is a test
with multiple
line
Para aclarar aún más:
##1##
this is a test
with multiple
line
##z##
##2##
test
##z##
Obviamente, solo daría lo que se especifica como punto de partida (ya que el punto final ##z##es siempre el mismo). Entonces, si utilizo ##2##en su lugar como punto de partida:
test
Esto daría lo anterior como salida.
Mi objetivo es convertir esto en una expresión regular compatible para vim. Estoy usando este sitio y el manual local como ayuda, pero no estoy seguro de por dónde empezar para convertir lo anterior a vim regex.
Respuestas
Una función extremadamente simple que hace el trabajo de manera mucho más 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
Nómbralo como quieras y luego hazlo, por ejemplo,
call Between('##1##', '##z##')
(que podrías vincular a una clave, quizás).
Para trabajar en todo el archivo, es posible que pueda usar :global(o incluso solo :%call Between(...)), o puede que necesite un bucle que envuelva esta función y recorra el archivo. En el caso de este último, usaría search(a:start)para encontrar el siguiente inicio y luego +estar dentro de la región anidada; entonces llamaría a la función. Esto es más rápido que llamar a la función en cada línea.
:g/END\|\%^/,/START\|\%$/s/.*//
Este comando global marca todas las líneas que coinciden ENDo el comienzo del archivo ( \%^). Luego procede a eliminar todo, desde las líneas marcadas hasta STARTel final del archivo ( \%$) utilizando el comando de sustitución s/.*//.
Un ejemplo de 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 |
Si no desea las líneas en blanco, puede reemplazar s/.*//por den el comando global.
Solo por diversión, recuerda que siempre puedes hacer
:%!sed '/start/\!d;s//&\n/;s/.*\n//;:a;/end/bb;$\!{n;ba};:b;s//\n&/;P;D'
Y eso sigue siendo "vim": P