Search and replace a multiline pattern

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Search and replace a multiline pattern

Jay Noronha
Hi,

I need to search and replace a possibly multi-line pattern.

I need to change the following search pattern (below)
cout << blah1 << blah2  << endl;
to  
LOGGER_DEBUG( m_logger,  blah1 << blah2 );

The blah1... blah_N could possibly be on different lines.

I tried the \_. pattern but it did not seems to work for me.
I seem to have got it to work partially using

g/cout *<<\([^;]\|\n\)*endl *;/s//LOG_DEBUG( m_logger, \1 );/g

But the \1 does not put the submatch in the replaced string,
but rather the character L instead.  

Is there something I am missing.  Is it because of the OR
condition in the pattern.

Also, is there a better/simpler/another way to do this.

Thanks
Jay






Reply | Threaded
Open this post in threaded view
|

Re: Search and replace a multiline pattern

Tim Chase-2
> I need to change the following search pattern (below)
> cout << blah1 << blah2  << endl;
> to  
> LOGGER_DEBUG( m_logger,  blah1 << blah2 );
>
> The blah1... blah_N could possibly be on different lines.

I can think of two ideas off the top of my head.  The first is to
make a prelim pass and make them all show up on the same line.

        g/cout[^;]*$/.,/;$/j

This will find all the cout lines that don't end in a semi-colon,
and join them through the next line that ends with a semi-colon.
  This then reduces the problem to an easier one (one that
doesn't involve newlines):

        :%s/cout\s\+<<\s*\(.*\)<<\s*endl;/LOGGER_DEBUG( m_logger, \1);


As my second idea, if you want to preserve all the various
new-lines, you might try something like

:%s/cout\s\+<<\s*\(\_[^;]*\)<<\s*endl;/LOGGER_DEBUG(m_logger, \1);

This does come out a little funky if you have

        cout << blah1
                << blah2
                << endl;

which then comes out

        LOGGER_DEBUG(m_logger, blah1
                << blah2
                );

with the widowed "backwards frowny wink" on the last line.

Both ways work for the examples I threw at it.

Hope this helps,

-tim




Reply | Threaded
Open this post in threaded view
|

Re: Search and replace a multiline pattern

Jay Noronha
Tim,

The second idea is just perfect :)

The following did just what I hoped for.
:%s/cout\s\+<<\s*\(\_[^;]*\)<<\s*endl;/LOGGER_DEBUG(m_logger, \1);

Thank you
Jay

--- In [hidden email], Tim Chase <vim@t...> wrote:

> > I need to change the following search pattern (below)
> > cout << blah1 << blah2  << endl;
> > to  
> > LOGGER_DEBUG( m_logger,  blah1 << blah2 );
> >
> > The blah1... blah_N could possibly be on different lines.
>
> I can think of two ideas off the top of my head.  The first is to
> make a prelim pass and make them all show up on the same line.
>
> g/cout[^;]*$/.,/;$/j
>
> This will find all the cout lines that don't end in a semi-colon,
> and join them through the next line that ends with a semi-colon.
>   This then reduces the problem to an easier one (one that
> doesn't involve newlines):
>
> :%s/cout\s\+<<\s*\(.*\)<<\s*endl;/LOGGER_DEBUG( m_logger, \1);
>
>
> As my second idea, if you want to preserve all the various
> new-lines, you might try something like
>
> :%s/cout\s\+<<\s*\(\_[^;]*\)<<\s*endl;/LOGGER_DEBUG(m_logger, \1);
>
> This does come out a little funky if you have
>
> cout << blah1
> << blah2
> << endl;
>
> which then comes out
>
> LOGGER_DEBUG(m_logger, blah1
> << blah2
> );
>
> with the widowed "backwards frowny wink" on the last line.
>
> Both ways work for the examples I threw at it.
>
> Hope this helps,
>
> -tim


Reply | Threaded
Open this post in threaded view
|

Re: Search and replace a multiline pattern

Tim Chase-2
> The second idea is just perfect :)
>
> The following did just what I hoped for.
> :%s/cout\s\+<<\s*\(\_[^;]*\)<<\s*endl;/LOGGER_DEBUG(m_logger, \1);

A small caveat (one of those things that comes to you when you
wake at 3:00am) that occurred to me is that if anything you're
printing has the terminating match in it *contained within a
string*, it will find that instead.  The counterpoint to that is
if the string has a semi-colon in it, it won't find the match.
They may be somewhat silly cases, but thought you might want to
be aware of them.

case1:
   cout << "ending with << endl;" << endl;

becomes

   LOGGER_DEBUG(m_logger, "ending with ");" << endl;

case2:
   cout << "testing; more testing" << endl;

is not found at all.  Or even worse, munging of example #2:

   cout << "testing; using cout << blah" << endl;

looks like it becomes

   cout << "testing; using LOGGER_DEBUG(M_logger, blah" );

All kinds of freaky weirdness.

Just so you know what sorts of things to be watching for in your
code.

-tim