Convierta sed regex en vim regex

Sep 09 2020

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

2 D.BenKnoble Sep 10 2020 at 03:16

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.

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

3 D.BenKnoble Sep 10 2020 at 06:31

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