DanielNeedles has asked for the wisdom of the Perl Monks concerning the following question:

I want to identify multi-line sub scopes of text and do text replacement within those scopes.

I can do this via VI
:g/<SCOPE>/s/<TEXT TO REPLACE>/<REPLACEMENT/g
For example:

I'd like to change:

if (@Agent eq 'XX') { @Agent='{XX}' }
To:
if (@Agent eq 'XX') { @Agent='{XX}' }

In this example I'd like to subscope to /if.*?\{/sm first before s:\n::g over the scope.

Can this be done easily outside writing code loops?

Replies are listed 'Best First'.
Re: Search and Replace Within Subscopes
by BrowserUk (Patriarch) on Jul 04, 2008 at 15:28 UTC

    Like this?

    #! perl -slw use strict; my $data = do{ local $/; <DATA> }; $data =~ s[(if.*?{)]{ ( my $subscope = $1 ) =~ s[\n][]g; $subscope; }smge; print $data; __END__ if (@Agent eq 'XX') { @Agent='{XX}' } if ( @Agent eq 'XX' ) { @Agent='{XX}' }

    Prints

    C:\test>junk7 if (@Agent eq 'XX'){ @Agent='{XX}' } if ( @Agent eq 'XX') { @Agent='{XX}' }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Looks good, but some of the syntax is a bit alien to me (in particular the use of [] and {} in '$x=~ s.{.}smge' Is there a good text/url on this kind of syntax?
        Those are alternate delimeters. See the "substitution operator" in perlop. Also read perlre. There is a wealth of information on perldoc.perl.org.
        You can use any pair of non-alphanumeric, non-whitespace charaters as delimiters of a regex pattern. So these regexes are equivalent:

        s/a/b/; s"a"b"; s^a^b^; s{a}{b}; s(a)[b];
        Only ' is an exception, this character prevents variable interpolation if used as delimiter

        Advantage is that you can use / inside them without escaping the character. Also it could be argued that {} [] or () as delimiters just look better, especially for complex patterns. Edit: Deleted one erraneous example found by ikegami

Re: Search and Replace Within Subscopes
by graff (Chancellor) on Jul 04, 2008 at 15:42 UTC
    I'm not sure I get the question (or the relation to vi), but if you're just talking about reformatting code as shown in your example, here's one way:
    { local $/; # go to slurp mode for input open( I, "<", "my_source_code" ) or die "my_source_code: $!"; $_ = <I>; close I; s/(if.*?)\s+{/$1 {/g; # fix spacing/line-breaks for "if .... {" open( O, ">", "my_new_source_code" ) or die "my_new_source_code: $ +!"; print O; close O; }
    Obviously, if the data being edited contains stuff like this:
    if ( "blah { blah } blah" ) { ...
    then it will get seriously screwed up simply not do what you intended, so maybe something more constrained:
    s/(if.*?\))[ \r\t]*\n\s+{/$1 {/; # fix spacing/line-breaks for " +if (...) {"
    which involves looking specifically for "if" plus some minimal number of non-line-break characters, followed by close-paren, followed a line-break (which might be surrounded by other kinds of whitespace). Even then, it's worth checking to see that the input and output meet your expectations.

    (updated second s/// example to include "\r")

      Thanks for the response. Though correct, I am trying to get around multiple passes and extra complexity. Ideally I am looking for something to first identify a series of scopes via REGEX and then do a regular search and replace on these scopes ignoring anything outside those scopes. This is a common problem to solve in config management. I am thinking there might be an easy way to do this since it is built in vi which came long before perl. There isn't anything in the new features additions in regex with 5.10 are there?
        There isn't anything in the new features additions in regex with 5.10 are there?
        I don't know, but you can see what's new for 5.10 at perldelta.
Re: Search and Replace Within Subscopes
by pc88mxer (Vicar) on Jul 04, 2008 at 15:48 UTC
      Maybe. I am looking to parse Netcool rules files which is basically a glorified if-then-else/switch-case-default stmts with assignments @x=,%x=,$x= and a handful of other functions. Also there are includes that need to be followed. I'm thinking the scope is small enough and the variances large enough that a tidy project would be larger than brute force coding.
        Well that certainly explains where @Agent eq 'XX' is coming from. And I just assumed that you didn't the difference between an array and a scalar. :-)