TransWikia.com

Convert sed regex to vim regex

Vi and Vim Asked on February 6, 2021

I got this sed regex I found:

sed '/start/!d;s//&n/;s/.*n//;:a;/end/bb;$!{n;ba};:b;s//n&/;P;D'

which basically outputs the content that is between a starting point and an end point.

##1##
this is a test
with multiple
line
##z##

and replacing start with ##1##, and end to ##z## would give:


this is a test
with multiple
line

If there are multiple occurrences of the ##1## and ##z##, then it would obviously show all the in-between text of said occurrence, like so:

##1##
this is a test
with multiple
line
##z##
##1##
this is a test
with multiple
line
##z##

to


this is a test
with multiple
line


this is a test
with multiple
line

To clarify even more:

##1##
this is a test
with multiple
line
##z##
##2##
test
##z##

would obviously give only what is specified as starting point (since the ending point ##z## is always the same).
So if i use ##2## instead as starting point:


test

This would give the above as output.

My goal is to convert this to a compatible regex for vim.
I’m using this site and the local manual as help but, I’m unsure where to start for converting the above to vim regex.

3 Answers

Just for fun, remember you can always do

:%!sed '/start/!d;s//&n/;s/.*n//;:a;/end/bb;$!{n;ba};:b;s//n&/;P;D'

And that’s still “vim” :P

Answered by D. Ben Knoble on February 6, 2021

:g/END|%^/,/START|%$/s/.*//

This global command marks all lines matching END or the beginning of file (%^). Then it proceeds to delete everything from the marked lines up to START or the end of file (%$) by using the substitution command s/.*//.

A side-by-side example:

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              |

If you don't want the blank lines, you can replace s/.*// by d in the global command.

Answered by Quasímodo on February 6, 2021

An extremely simple function which does the job far more idiomatically:

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

Name it whatever you want, and then do, e.g.,

call Between('##1##', '##z##')

(which you could bind to a key, perhaps).

To work on the whole file, you might be able to use :global (or even just :%call Between(...)), or you may need a loop wrapping this function and traversing the file. In the case of the latter, I would use search(a:start) to find the next start and then + to be inside the nested region; then I would call the function. This is faster than calling the function on every line.

Answered by D. Ben Knoble on February 6, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP