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

Is it possible to assign a value to a variable and then do a substitution on it in a single statement? For example suppose I want to start with a URL, remove a known host-domain name, then assign the remaining dir/filename to a variable. With two statements you could say
$dirfilename = $url; $dirfilename = s|http://foo.bar.com/||;
But is there a way to do the same thing in one statement?
$dirfilename = $url =~ s|http://foo.bar.com/||;
will not work because this does the substitution on $url then assigns a 1 to $dirfilename to indicate the successful substitution.

Many thanks....

Steve

Replies are listed 'Best First'.
Re: Assign & substitute in one statement?
by Zaxo (Archbishop) on Jun 13, 2004 at 22:09 UTC

    Sure, just write parens in their precedence-adjusting role: ($dirfilename = $url) =~ s|\Qhttp://foo.bar.com/\E||; Your substitution is corrected here for the presence of re metacharacters.

    After Compline,
    Zaxo

      Sure, just write parens in their precedence-adjusting role
      ...and their list context inducing role.

      Arjen

      Update: edan is right. I was thinking about the m// operator which does return the matched subexpressions in list context.

        I had to think about it for a minute, and reread parts of the perlop manpage, but Zaxo is right, and you're wrong. Sorry.

        The s/// operator always returns the number of substitutions made, regardless of context. The parentheses here are indeed adjusting the precedence, because normally the =~ operator binds more tightly than assignment operators, = in this case. That's why without parens you first do the substitution, then assign the result to the variable. Putting the parens around the assignment forces that to happen first. In comes the handy lvalue property of assignment, so modifying the assignment with =~ has the effect of modifying the left-hand argument of the assignment. In the words of perlop:

        Modifying an assignment is equivalent to doing the assignment and then modifying the variable that was assigned to.

        --
        edan

Re: Assign & substitute in one statement?
by kesterkester (Hermit) on Jun 13, 2004 at 22:04 UTC
    If you enclose the assignment in parens, and then do the substitution after the parens, you should get exactly what you want:

    perl -le 'use strict; my $str1 = "test"; ( my $str2 = $str1 ) =~ s/t/m/g; print $str2'
Re: Assign & substitute in one statement?
by dfaure (Chaplain) on Jun 14, 2004 at 06:37 UTC

    From the Perl Cookbook, recipe 6.1.Copying and Substituting Simultaneously:

    You can even use this technique on an entire array:

    @bindirs = qw( /usr/bin /bin /usr/local/bin ); for (@libdirs = @bindirs) { s/bin/lib/ } print "@libdirs\n"; __OUTPUT__ /usr/lib /lib /usr/local/lib

    The parentheses are required when combining an assignment if you wish to change the result in the leftmost variable. Normally, the result of a substitution is its success: either "" for failure, or the number of times the substitution was done. Contrast this with the preceding examples where the parentheses surround the assignment itself. For example:

    ($a = $b) =~ s/x/y/g; # copy $b and then change $a $a = ($b =~ s/x/y/g); # change $b, count goes in $a

    Update: made a Q&A node of it: How do I assign & substitute in one statement?

    HTH, Dominique
Re: Assign & substitute in one statement?
by Anonymous Monk on Jun 14, 2004 at 18:27 UTC
    Try: ($dirfilename) = $url =~ s|http://foo.bar.com/||;
      And then please realize that it won't work { grin }. The binding will still go first, and $dirfilename will just return a scalar.