Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `$str1 =~ "foo"` recognized as `$str1 =~ m/foo/` (and not a syntax error)?

Tags:

regex

perl

I recently saw code from someone who's not familiar with Perl. He wanted to compare two strings for equality but didn't know about the eq operator, so he used =~ like this:

my $str1 = 'foobar';
my $str2 = 'bar';
if ( $str1 =~ $str2 ) {
    print "strings are equal\n";
}

Another snippet was

if ( $str1 =~ "foo" ) {
    print "string equals 'foo'\n";
}

Of course it should simply read $str1 eq $str2 and $str1 eq "foo" to avoid false-positives.

I run the code through Deparse and it said everything is ok:

$ perl -MO=Deparse -e 'use strict; 
                       use warnings; 
                       my $str1="foobar"; 
                       my $str2="bar"; 
                       $str1 =~ $str2; 
                       $str1 =~ "bar";'
use warnings;
use strict;
my $str1 = 'foobar';
my $str2 = 'bar';
$str1 =~ /$str2/;
$str1 =~ /bar/;
-e syntax OK

I looked through the docs, but from my understanding the situation is as follows:

  • The general syntax is m/pattern/.
  • Either use m and a delimiter of your choice instead of / (but be aware that ' and ? have special meaning)
  • Or leave off the m but then the delimiter must be /.

But apparently Perl understands $str1 =~ "foo" as $str1 =~ m/foo/ although no m is present. Why is that? I'd expected that to be a syntax error.

like image 859
PerlDuck Avatar asked Sep 14 '16 19:09

PerlDuck


2 Answers

I'd expected that to be a syntax error.

Quoting the documentation for =~ in perlop,

If the right argument is an expression rather than a search pattern, substitution, or transliteration, it is interpreted as a search pattern at run time.


But apparently Perl understands $str1 =~ "foo" as $str1 =~ m/foo/ although no m is present. Why is that?

Why not? I can't think of a reason not to have =~ imply a match operator if there's no match, substitution or transliteration operator on its RHS. I'd use

$s =~ /foo/

over

$s =~ "foo"

but I have used

$s =~ $re

Especially when the value of $re is a pattern compiled by qr//.

like image 189
ikegami Avatar answered Nov 20 '22 01:11

ikegami


The =~ operator expects a scalar expression no the left and a pattern match on the right. From the documentation:

Binary "=~" binds a scalar expression to a pattern match. Certain operations search or modify the string $_ by default. This operator makes that kind of operation work on some other string. The right argument is a search pattern, substitution, or transliteration. The left argument is what is supposed to be searched, substituted, or transliterated instead of the default $_ .
...
If the right argument is an expression rather than a search pattern, substitution, or transliteration, it is interpreted as a search pattern at run time.

The actual interpretation of the right hand side can be... tricky. The details can be found in the Perl Documentation's "Gory Details of Parsing Quoted Constructs", the summary of which is:

When presented with something that might have several different interpretations, Perl uses the DWIM (that's "Do What I Mean") principle to pick the most probable interpretation. This strategy is so successful that Perl programmers often do not suspect the ambivalence of what they write. But from time to time, Perl's notions differ substantially from what the author honestly meant.
...
The most important Perl parsing rule is the first one discussed below: when processing a quoted construct, Perl first finds the end of that construct, then interprets its contents. If you understand this rule, you may skip the rest of this section on the first reading. The other rules are likely to contradict the user's expectations much less frequently than this first one.

like image 44
Mr. Llama Avatar answered Nov 20 '22 02:11

Mr. Llama