Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re: $1 in variable regex replacement string

by tadman (Prior)
on Feb 12, 2003 at 22:32 UTC ( [id://234849]=note: print w/replies, xml ) Need Help??


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

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.

Replies are listed 'Best First'.
Re: Re: $1 in variable regex replacement string
by jsprat (Curate) on Feb 13, 2003 at 01:57 UTC
    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.
Re: Re: $1 in variable regex replacement string
by tachyon (Chancellor) on Feb 12, 2003 at 22:48 UTC

    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'

        I'm not sure why you're using a hash there when this should do the trick:
        sub safeswitch { no strict 'refs'; my @P = map { $$_ } 0..@+; $_[0] =~ s/\$(\d+)/$P[$1]/g; $_[0]; }
        As far as I can tell, you're only using %seen to count?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://234849]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2024-04-16 07:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found