You can use a filter. I would probably use sed
for arbitrary multi-line matching.
There is a drawback in that there is no way in sed
to do non-greedy matching, but in certain cases you can work around that. (For example, add only one line at a time until you get a match, then do the substitute, as below.) Your examples aren't using non-greedy matching in the first place, so:
:.,$!sed '/<body/{;:loop;s@<body.*/body>@@;t;$b;N;bloop;}'
Here's an example command. This will filter lines from the current line through the end of the file. Until it finds the match <body
it will output each line exactly as it inputs. When it hits <body
it enters a loop (conveniently labeled with :loop
. The label itself does nothing but can be branched to later.) sed
runs a substitute command, greedily matching <body.*/body>
and deleting it if found (using @ as delimiter to avoid needing to escape the /
.) If the substitute command actually did something, t
exits the loop and sed
outputs the text as it was changed by the substitute command, and then proceeds to the next line. Otherwise, sed
continues: the $b
command is ignored unless sed
is on the last line to be filtered. N
adds in the next line to what is being considered, with a newline in between, and the b
ranch command branches to the label loop
. Then the substitute command is run again, now on two lines, and if no match then it is run on three lines, until it either finds a match (at which point the t
command breaks the loop) or until the end of the lines to be filtered, at which point $b
causes a b
ranch and exits the loop, outputting the lines without filtering.
(sed
is a whole language in itself. It's not very complicated—actually if you're familiar with Ex commands you will recognize a lot of vim
's heritage in sed
's syntax—but it is very concise. I've heard it called the "assembly language of text editing" and it is a very apt description.)
Hope this is helpful. I'm happy to clarify anything more you'd like on this, or tailor the example better for your needs. :)
g/foo/ .,/foo/d
(replacing foo with what works for you, of course)?:g/<body/,/body>/d
seems to work (as a side-effect, it'll remove the whole lines with it, but it almost works as expected). You can add that into your answer.:%s/<body>\(.|\n\)*<\/body>//
?:%s/<body\_.\{-}body>//
). Can you post the answer then?