in reply to Re: $1 in variable regex replacement string
in thread $1 in variable regex replacement string

For example you would not want it passed:

$repl = '\";`hacked`;\"';

You can make this a whole lot safer (maybe even totally safe) with a suitable sanitization of $repl

sub munge_string { my ( $str, $pat, $repl ) = @_; # make $repl safe to eval $repl =~ tr/\0//d; $repl =~ s/([^A-Za-z0-9\$])/\\$1/g; $repl = '"' . $repl . '"'; $str =~ s/$pat/$repl/eeg; return $str; }

cheers

tachyon

s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Replies are listed 'Best First'.
Re: $1 in variable regex replacement string
by tadman (Prior) on Feb 12, 2003 at 22:32 UTC
    Drawing on dvergin's idea, what about this?
    sub safeswitch { my @P = (undef,$1,$2,$3,$4,$5,$6,$7,$8,$9); $_[0] =~ s/\$(\d)/$P[$1]/g; $_[0]; } my $str = "abcdefghijafjafjkagjakg"; my $pat = '(a.)'; my $repl = '$1 '; $str =~ s/$pat/safeswitch($repl)/eg; print $str,$/;
    The advantage here is that you don't end up re-evaluating the function code each time, just the function call.
      This thread has turned into the "Perl Quiz of the Week" #1! ;-)
      Write a subroutine, 'subst', which gets a string argument, $s. It should search $s and replace any occurrences of "$1" with the current value of $1, any occurrences of "$2" with the current value of $2, and so on.

      For example, if $1, $2, and $3 happen to be "dogs", "fish" and "carrots", then

      subst('$2, $1 and $3')
      should return
      "fish, dogs, and carrots"
      dominus' post-mordem analysis of this problem can be found here. He offers several solutions and some discussion of why (and why not) to use them.

      Very nice! So all wrapped up and ready to go you would have:

      my $str = "abcdefghijafjafjkagjakg"; my $pat = '(a.)'; my $repl = '$1 '; print munge($str,$pat,$repl); =head2 munge( STRING, PATTERN, REPLACEMENT ) The munge function takes three arguments and returns a string. The first argument is the STRING to be modified. The modification is performed by s/PATTERN/REPLACEMENT/g. The main advantage of this function is that REPLACEMENT can contain $1, $2 etc that have been captured by PATTERN These values are safely interpolated prior to the substitution being made. =cut sub munge { my($str, $pat, $repl) = @_; $str =~ s/$pat/_safeswitch($repl)/eg; return $str; } # used by munge function to safely interpolate # $1, $2 etc into the replacement string sub _safeswitch { my @P = (undef,$1,$2,$3,$4,$5,$6,$7,$8,$9); $_[0] =~ s/\$(\d)/$P[$1]/g; $_[0]; }

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        # used by munge function to safely interpolate # $1, $2 etc into the replacement string sub _safeswitch { my @P = (undef,$1,$2,$3,$4,$5,$6,$7,$8,$9); $_[0] =~ s/\$(\d)/$P[$1]/g; $_[0]; }

        If I read the above correctly, it'll only handle 9 sets of capturing parens, and it's possible that we may have matched more than 9 sets.

        My fix is to dynamically build @P to size.

        # used by munge function to safely interpolate # $1, $2, etc. into the replacement string sub _safeswitch { my %seen; @seen{@+} = (undef) x @+; my @P; { no strict 'refs'; # allow $$_ to be $1, $2, etc. no warnings 'unitialized'; # allow undef as $$_ @P = map { $$_ } undef, 1 .. scalar keys %seen; } $_[0] =~ s/\$(\d+)/$P[$1]/g; $_[0]; }

        And a test:

        #!/usr/bin/perl use strict; use warnings; my $str = 'abcdefghijklmnopqrstuvwxyz'; my $pat = '(.).(.).(.)..(.).(.)(.)(.).(.)(.)(.).(.)(.)(.)(.).+'; my $repl = '$5$14$12$13 $1$8$9$13$4$3$11 $10$3$11$7 $4$1$2$6$3$11'; print munge( $str, $pat, $repl ), "\n"; sub munge { my($str, $pat, $repl) = @_; $str =~ s/$pat/_safeswitch($repl)/eg; return $str; } # used by munge function to safely interpolate # $1, $2, etc. into the replacement string sub _safeswitch { my %seen; @seen{@+} = (undef) x @+; my @P; { no strict 'refs'; # allow $$_ to be $1, $2, etc. no warnings 'uninitialized'; # allow undef as $$_ @P = map { $$_ } undef, 1 .. scalar keys %seen; } $_[0] =~ s/\$(\d+)/$P[$1]/g; $_[0]; } exit;
        UPDATE
        • my %seen
        • no warnings 'unitialized';
        • allow multiple digits in s/// in _safeswitch
        • add test case

        Incidentally, the line @seen{@+} = (undef) x @+; is a faster way to build
        such a hash than the various equivalents ( %seen = map { $_ => undef } @+;
        most notable among them for being popular and 4x slower).

        I discovered this just today ;)

        blyman
        setenv EXINIT 'set noai ts=2'