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

How do I replace the \ character in a file except those inside the comments delimited by \* and *\. eg., \AFZ\BJK \*\AFZ...*\ should be AFZBJK \*\AFZ...*\

Replies are listed 'Best First'.
Re: Replace character not inside comments
by Abigail-II (Bishop) on Sep 05, 2002 at 14:35 UTC
    Assuming the string to be modified is in $_:
    $_ = do {my $t = ""; $t .= defined $1 ? do {(my $t = $1) =~ y/\\//d; $t} : $2 while /((?:[^\\]+|\\(?!\*))+)|(\\\*(?:[^*]+|\*(?!\\) +)+\*\\)/g; $t };
    Abigail
Re: Replace character not inside comments
by thpfft (Chaplain) on Sep 04, 2002 at 19:24 UTC

    Japhy can probably tell you how to do it in one go, with much looking about, but I'll have to settle for three lines: first remove and store comments, then strip the backslashes, then restore the comments. This seems to work:

    my $test = q|\AFZ\BJK \*\AFZ...*\ |; my @comments; $test =~ s/(\\\*.*?\*\\)/ push @comments, $1; '%%comment%%' /eg; $test =~ s/\\//g; $test =~ s/%%comment%%/ shift @comments /eg; print $test;

    Any old marker will do as long as it doesn't appear in your text: something long and random would probably be best. %%comment%% was just the first thing that came into my head.

    ps. goes clunk, i know, but easy to follow

      how would i make this work if the comment spanned more than 1 line?

        just adding an s modifier to each regex ought to do it: it'll then treat the whole thing as if it were one line (or, strictly, it'll treat line-endings as just another character), as the early parts of perlre will explain. I should have put that in, but your example was just one line so I didn't bother:

        $test =~ s/(\\\*.*?\*\\)/ push @comments, $1; '%%comment%%' /egs; $test =~ s/\\//gs; $test =~ s/%%comment%%/ shift @comments /egs;
Re: Replace character not inside comments
by Ido (Hermit) on Sep 04, 2002 at 19:41 UTC
    I couldn't come up with a regex to catch those, but only one that would catch all other chars(as long as comments don't nest). I think you could use the following:
    $test=q|\AFZ\BJK \*\AFZ...*\ |; $new.=$1 while $test=~/([^\\]|\\\*.*?\*\\)/g;
    UPDATE: Or, if comments do nest perhaps this will do:
    $test=q|\AFZ\BJK \*\A\*F*\Z...*\ |; $comment=qr/\\\*(?:[^\\]*|\\[^*]|(??{$comment}))*?\*\\/; $new.=$1 while $test=~/([^\\]|$comment)/g;
Re: Replace character not inside comments
by Vennis (Pilgrim) on Sep 05, 2002 at 14:14 UTC
    This seems to work:
    $test ="\\AFZ\\BJK \\\*\\AFZ...\*\\"; $span = 0; # Span is a span counter foreach( split(/(\\\*|\*\\)/,$test) ){ # Split on spans keeping the co +mmenttags if($_ eq '\\*'){ # See if its a comment-start $span ++; } elsif($_ eq '*\\'){ # if it's a comment-end $span --; } elsif($span eq 0){ # Only if not in comment $_=~s/\\//igs; } $newtest.=$_; }
    Edited: Made an elsif instead of several ifs.
    Edited: I got a negative vote, i guess because the lack of comment. I found the question a challenge for myself, but i forgot to share the thoughts. Therefor more comment added.