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

Hi Monks, I want to do a nested replace. But I do not know how to code it.

I want to delete from string(= complete file with multiple lines) everything between "/*" and */, but all "\n" should be untouched.

My Idea was to search for "/*..*/ and than replace in a second step all characters not equal to \n with ""

Here my construct, which does not work :-(
s:/\*([\0-\255]*?)\*/:($1=~s/[^\n]//g):g; ^^^^^^^^^^^^^^^^ nested replace is seen as text +and not executed
Can you tell me what I how to code it? By the way: Is there a shorter expression for : [\0-\255]? Thanks !!

Replies are listed 'Best First'.
Re: nested replace
by choroba (Cardinal) on Mar 18, 2016 at 08:56 UTC
    If you want the dot to match anything including newlines, use the /s modifier. To evaluate the replacement as code, use the /e modifier.
    use Syntax::Construct qr{ /r }; $string =~ s:/ \* (.*?) \*/ : $1 =~ s/[^\n]//gr :gsex;

    In older Perls without /r :

    $string =~ s:/ \* (.*?) \*/ : (my $x = $1) =~ s/[^\n]//g; $x :gsex;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Thanks choroba, for your comments of the modifier. I used:

      $string =~ s:/ \* (.*?) \*/ : (my $x = $1) =~ s/[^\n]//g; $x :gsex;
      but it replaces the text within the "/*...*/" with the a position of the text.
      ">/*x*/<" is converted in ">1<" instead of "><" ">/*x\nx\nx*/<" is converted in ">3<" instead of ">\n\n<"
        Weird, works for me in 5.8.3, 5.10.1, 5.20.1, and 5.22.1.
        $ perl -lwe ' $string = q<a/*z*/b>; $string =~ s: /\* (.*?) \*/ : (my $x = $1) =~ s/[^\n]//g +; $x :gsex; print $string; ' ab
        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

        You probably forgot the final "; $x" in the replacement part of the outer regex. Without it, the inner substitution returns the number of times it matched.

        Sorry !

        Your code works correct ! Thanks!!

        In my code I did not have the last $x

        $string =~ s:/ \* (.*?) \*/ : (my $x = $1) =~ s/[^\n]//g; $x :gsex; ^^
Re: nested replace
by AnomalousMonk (Archbishop) on Mar 18, 2016 at 13:22 UTC

    Just a parenthetic note: From Perl version 5.14 on, the  /r modifier for  s/// and  tr/// operators allows them to return the substituted/transformed string for a slightly simpler expression:

    c:\@Work\Perl\monks>perl -wMstrict -le "my $c = qq{foo /* bar \n baz \n boff \n */ fum}; print qq{<<$c>>}; ;; $c =~ s{ /[*] (.*) [*]/ }{ $1 =~ s{[^\n]}{}xmsrg }xmsge; print qq{[[$c]]}; " <<foo /* bar baz boff */ fum>> [[foo fum]]
    Works with  $1 =~ tr{\n}{}cdr as well. See  s/// in Regexp Quote-Like Operators, and  tr/// in Quote-Like Operators.


    Give a man a fish:  <%-{-{-{-<

Re: nested replace
by Anonymous Monk on Mar 18, 2016 at 09:28 UTC

    Another alternative:

    use Regexp::Common 'comment'; $str=~s/($RE{comment}{C})/($a=$1)=~s#[^\n]##g;$a/ge;
Re: nested replace
by Discipulus (Canon) on Mar 18, 2016 at 08:57 UTC
    i'm not an expert but i think you need an e as regex modifier.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: nested replace
by Anonymous Monk on Mar 18, 2016 at 08:55 UTC

    generic "pattern" hahyaha

    $var =~ s{(yada)}{OtherSubstitute("$1")}ge; sub OtherSubstitute { my( $in ) = @_; ## $in =~ s{yada}{yada}g; my $numlines = $in =~ tr/\n/\n/; ## count return "\n" x $numlines; }