in reply to Replace only unescaped metachars

You really do need a parser, so while a pair of substitutions is possible, it's not the most appropriate.

my %conv = ( '*' => '?', '?' => '#' ); my $conv = quotemeta(join('', keys(%conv))); my $string = 't?e\\\\xt\\\\* with escapes\\*'; my $result = $string; for ($result) { s/(?<!\\)((?:\\{2})*)([$conv])/$1$conv{$2}/g; s/\\(.)/$1/sg; } print($result, "\n");

Your code can be simplified (visually):

my $string = 't?e\\\\xt\\\\* with escapes\\*'; my $result = ''; for ($string) { /\G \\(.) /xgcs && do { $result .= $1; redo; }; /\G \* /xgcs && do { $result .= '?'; redo; }; /\G \? /xgcs && do { $result .= '#'; redo; }; /\G (.) /xgcs && do { $result .= $1; redo; }; } print($result, "\n");

An optimization of the above:

my $string = 't?e\\\\xt\\\\* with escapes\\*'; my $result = ''; for ($string) { $result .= $1 if /\G ([^\\*?]+) /xgcs; /\G \\(.) /xgcs && do { $result .= $1; redo; }; /\G \* /xgcs && do { $result .= '?'; redo; }; /\G \? /xgcs && do { $result .= '#'; redo; }; } print($result, "\n");

Replies are listed 'Best First'.
Re^2: Replace only unescaped metachars
by Anonymous Monk on Feb 23, 2007 at 07:50 UTC
    Ah, yes, this is the clever part I was missing:
    (?<!\\) ((?:\\{2})*)
    It makes sure that only unescaped metachars are converted (all preceding escapes are even).
    Thanks!

    But why is the following an optimization (against my code)?:
    for ($string) { $result .= $1 if /\G ([^\\*?]+) /xgcs; /\G \\(.) /xgcs && do { $result .= $1; redo; }; /\G \* /xgcs && do { $result .= '?'; redo; }; /\G \? /xgcs && do { $result .= '#'; redo; }; }
    If I see it right, both versions try to keep the common case at the beginning and have to walk through the other regexes until the first match. (Besides the 'redo' irritated me until I read in the docs that it doesn't redo do-blocks) But still thank you very much for this too, it is always good to have variations at hand.
    -Michael

      But why is the following an optimization (against my code)?:

      It's an optimization against *my* code. You had a similar optimization already. (Your first elsif would have to be an if to be the same.)

      Besides the 'redo' irritated me until I read in the docs that it doesn't redo do-blocks

      redo, last and next only work on the various for/foreach blocks, while blocks and bare blocks. They don't work on non-loop blocks such as if, do, eval and sub blocks.