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

Hi monks

I'm confused. This snippet behaves:

my $text = "this text"; $text =~ /this/that; print $text;
and prints 'that text'.

But not this:

my $text = "this text"; print $text =~ /this/that/;
It prints '1', clearly the truth of the statement, but why?
What's the correct way to do it inline?

Replies are listed 'Best First'.
Re: Inline substitution regex
by kennethk (Abbot) on Sep 28, 2009 at 22:14 UTC
    As you can read in Search and replace in perlretut, substitution returns the number of substitutions, so that is what you are passing to print.

    As an example,

    #!/usr/bin/perl use strict; use warnings; my $string = 'I like cats. I think cats are nice.'; print $string =~ s/cat/dog/g;
Re: Inline substitution regex
by ikegami (Patriarch) on Sep 28, 2009 at 23:03 UTC

    [ In the future, post the code you actually ran rather than making stuff up. Your code does NOT produce the output you specified. In fact, it doesn't run at all. ]

    I don't understand why, but it's a common misconception that operators return their left-hand argument. Why you expect the following to print 3?

    print( 3 + 4 );

    Then why would expect the following to print $text?

    print( $text =~ s/this/that/ );

    Operators are documented in perlop. s/// is no exception. Search for s/PATTERN/REPLACEMENT/ in the "Regexp Quote-Like Operators" section. It is documented to return the number of substitutions made.

    What's the correct way to do it inline?

    I'd say it's not correct to do it inline

    $text =~ s/this/that/; print $text;

    You can manage with the following, but you're complicating your code again.

    print( do { $text =~ s/this/that/; $text } );

      Ok I almost understand it now.

      It's hard to see s/this/that/ as an opperator! Because, err ... it looks like an expression, just like 3 + 4 is, in the following which prints 7 as expected.

      my $var; print $var = 3 + 4 . "\n"; # Just for illustration!

      Please do be a little more forgiving of beginners ;-) The print example code is just a clear way of illustrating my confusion. Here is the original code snippet with the incorrect line commented and the correct one as per your helpful explanations.

      foreach (keys %{$ref_cookie}) { # push(@{$self->{cookies}}, {$_=~s/^-//}, $ref_cookie->{$_}}); push @{$self->{cookies}} , do{$_=~/^-(.*)/;$1}, $ref_cookie->{$_}); }

      Thanks

        It's hard to see s/this/that/ as an opperator! Because, err ... it looks like an expression

        s/this/that/ *is* an expression. The expression consists of the substitution operator and its two operands (the search pattern and the replacement expression).

        $text =~ s/this/that/ is also an expression. The expression consists of the binding operator (=~) and its two operands, the value to bind ($text) and the previously mentioned expression.

        The binding operator does not return its LHS. It returns its RHS. As for the substitution operator, it does not return the variable to which it is bound.

        the following which prints 7 as expected.

        I'm not sure what you are saying. Are you saying $var = 3+4 returns the result of 3+4, so $text =~ s/this/that/ should return the result of s/this/that? That's wrong for two reasons.

        • $var = 3+4 does not return the result of 3+4. Scalar assignment returns its LHS operand as an lvalue, so $var is returned here.

        • And you're wrong about a corolation, because $text =~ s/this/that/ does return the result of s/this/that. The binding operator returns the result of its RHS operand.

        I didn't say it's not possible for an operator to return it's LHS. As you've shown, scalar assignment returns its left-hand side. There's also boolean operators. They return either their LHS or RHS operands.

        Better solution:

        foreach (keys %{$ref_cookie}) { push @{$self->{cookies}}, /^-(.*)/, $ref_cookie->{$_}; }

        The match operator returns what it captures.

        Update: Remove trailing paren

      I don't understand why, but it's a common misconception that operators return their left-hand argument. Why you expect the following to print 3?

      print( 3 + 4 );

      Then why would expect the following to print $text?

      print( $text =~ s/this/that/ );

      Well wrong example, IMHO the misconception is motivated by

      print( $num = 3 + 4 );
      which prints 7!

      Occasionally it's a trap for me, too! 8)

      IIRC the binding operator =~ will be changed in Perl6, which thankfully avoids this misleading association!

      Cheers Rolf

        the misconception is motivated by

        It's clearly not generalisable since none of the following doesn't print 7:

        print( 2 + 3 + 4 ); # 9 print( 2 || 3 + 4 ); # 2 print(0+( ($var) = 3 + 4 )); # 1
Re: Inline substitution regex
by Marshall (Canon) on Sep 28, 2009 at 22:37 UTC
    Turn warnings and strict both "on".
    #!/usr/bin/perl -w use strict; my $text = "this text"; $text =~ /this/that; #### WRONG syntax ##### print $text; #------ Bareword found where operator expected at C:\TEMP\temp1.pl line 5, near "/this/that" (Missing operator before that?) syntax error at C:\TEMP\temp1.pl line 5, near "/this/that" Execution of C:\TEMP\temp1.pl aborted due to compilation errors. =============================================== #!/usr/bin/perl -w use strict; my $text = "this text"; $text =~ s/this/that/; #note s needed as well as '/' after "that" print $text; #prints: that text
    Your second question:
    my $text = "this text"; print $text =~ /this/;
    The result of a match is True/False.  print $text =~ m/this/; is the same thing.
    #match can be used like a boolean T/F if($text =~ m/this/) { blah ...}
    Update:

     $text =~ /this/ vs $text =~ m/this/ is a matter of style. When using the default '/' you can leave off the "m". if you use a different character to delimit the match, say  $text =~ m|this|;, then you definitely need the "m".

Re: Inline substitution regex
by johngg (Canon) on Sep 28, 2009 at 22:17 UTC

    You could use a do block.

    $ perl -le ' > $text = q{this text}; > print do{ $text =~ s{this}{that}; $text };' that text $

    I hope this is helpful.

    Cheers,

    JohnGG

    Update: Applying the same principle but using map saves some typing.

    $ perl -le ' > $text = q{this text}; > print map { s{this}{that}; $_ } $text;' that text $

    As others have pointed out though, your code will be clearer to those who follow if you separate the substitution and the print.