http://qs1969.pair.com?node_id=545486

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

Hi,

I have a question regarding delaying interpolation of a variable when it is used in a regular expression. The below code snippet demonstrates the problem

%cat test.pl

#!/usr/bin/perl use strict; my $line = "System has tool zigzag version 3.6"; my $match = 'System\s+has\s+tool\s+([0-9a-zA-Z_-]+)\s+version\s+(.*)'; my $replace = 'System has tool $1 version ABC'; $line =~ s/$match/$replace/g; print "Line after replacement: $line \n";
When I execute the above code the output I get is :

%./test.pl

Line after replacement: System has tool $1 version ABC

The output I need is :

Line after replacement: System has tool zigzag version ABC

How do I get $1 to be interpolated in the replacement pattern ? I tried other variants like : e,ee etc but none yeild the result I need.

Replies are listed 'Best First'.
Re: delayed variable interpolation in a regular expression
by davido (Cardinal) on Apr 25, 2006 at 07:27 UTC

    You were close, but forgot one thing. If you use /ee, you need another set of quotes, and they should be "interpolating" quotes (ie, "...."). Try the following:

    use strict; use warnings; my $line = "System has tool zigzag version 3.6"; my $match = 'System\s+has\s+tool\s+([0-9a-zA-Z_-]+)\s+version\s+(.*)'; my $replace = '"System has tool $1 version ABC"'; $line =~ s/$match/$replace/eeg; print "Line after replacement: $line \n";

    Dave

Re: delayed variable interpolation in a regular expression
by ashokpj (Hermit) on Apr 25, 2006 at 07:42 UTC
    Try like this.
    #!/usr/bin/perl my $line = "System has tool zigzag version 3.6"; my $match = 'System\s+has\s+tool\s+(\w)\s+version\s+(.*)'; my $replace = '"System has tool $1 version ABC"'; $line =~ s/$match/$replace/eg; print "Line after replacement: $line \n"
Re: delayed variable interpolation in a regular expression
by Tanktalus (Canon) on Apr 25, 2006 at 15:31 UTC
Re: delayed variable interpolation in a regular expression
by johngg (Canon) on Apr 25, 2006 at 09:12 UTC
    In your line

    my $match = 'System\s+has\s+tool\s+([0-9a-zA-Z_-]+)\s+version\s+(.*)';

    you have a character class [0-9a-zA-Z_-] but if you are intending that a hyphen is part of the class you must place it first in the class like this [-0-9a-zA-Z_]. Anywhere else in the class the hyphen denotes a range so your one is a class of 0 to 9, a to z, A to Z and underscore to nothing.

    Cheers,

    JohnGG

      I've always thought that the first position was for the closing square bracket, and the hyphen should be placed at the end of the character class. From perlretut: If ’-’ is the first or last character in a character class, it is treated as an ordinary character; "[-ab]","[ab-]" and "[a\-b]" are all equivalent. It's interesting to note that the same doesn't apply to the closing square bracket:

      $ perl -e 'my $s="-]"; print "a\n" if $s =~ /[___]]/' $ perl -e 'my $s="-]"; print "a\n" if $s =~ /[]___]/' a $ perl -e 'my $s="-]"; print "a\n" if $s =~ /[___-]/' a $ perl -e 'my $s="-]"; print "a\n" if $s =~ /[-___]/' a

      Update: In Perl, ']' has to be escaped so the first and seconds examples above are wrong. It is in grep, where it suffices to put the bracket at the beginning of the character class.

      --
      David Serrano

        David, you were correct the first time and your second example is fine. ] can be the first character in a class without being escaped.

        H:\>perl -e "$_='a';/[]a]/?print 'Y':print 'N'" Y H:\>
        On an XP box (which is why you see the reversed quote notation). I also believe you're absolutely correct about the hyphen being acceptable as the last character (it's not "underscore to nothing").


        -----------------
        s''limp';@p=split '!','n!h!p!';s,m,s,;$s=y;$c=slice @p1;so brutally;d;$n=reverse;$c=$s**$#p;print(''.$c^chop($n))while($c/=$#p)>=1;
        I thought it had to be first but obviously I was wrong. Apologies to wannabeperlie. Thank you for the correction. Another new thing learnt.

        Cheers,

        JohnGG