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

I had the following condition in a script that filtered out certain lines:

if (not $inst =~ /lea/i) { # do things }

This worked as intended, the condition being wrong if the $inst string variable contains "lea" as a substring. Now I had another variable which I would also like to check to do the same filtering. This is what I tried: (Note that I assume the \b are irrelevant.)

if (not $label.$inst =~ /\blea\b/i) { # do things }

A few hours later I found that this condition is never true, assuming $label and $inst both being nonempty strings and both not strings of a single zero "0". I eventually fixed this like so:

if (not (($label.$inst) =~ /\blea\b/i)) { # do things }

This works as expected: The concatenation happens first, then it is matched against the pattern, and then the pattern result is negated in a boolean sense.

However, I'm wondering why both additional sets of parens are needed here. According to perlop the match operator "=~" has a higher precedence than the string concatenation ".", so I understand why I need the innermost parens - to have perl concatenate first before applying the match pattern. But the same page states that the "not" operator has a lower precedence than both of the others. So I would expect the following to work the way I want, but it doesn't seem to:

if (not ($label.$inst) =~ /\blea\b/i) { # do things }

So what exactly is going on there? Is the "not" somehow applied to "($label.$inst)" before the match operator is processed?

In my repo this has additional conditions in the same "if" condition but some light testing seems to indicate this isn't the cause of the problem. Here's two simple stand alone test scriptlets:

$ perl -e 'use warnings; use strict; my $pre="foo"; my $suf="bar"; pri +nt (not (($pre.$suf) =~ /lea/i)); print "\n";' 1 $ perl -e 'use warnings; use strict; my $pre="foo"; my $suf="bar"; pri +nt (not ($pre.$suf) =~ /lea/i); print "\n";' $

I expected both scriptlets to display a "1" (true condition output).

  • Comment on Why does NOT operator on match operator on string concatenation require two pairs of parens?
  • Select or Download Code

Replies are listed 'Best First'.
Re: Why does NOT operator on match operator on string concatenation require two pairs of parens?
by GrandFather (Saint) on Nov 25, 2024 at 00:28 UTC

    Not an answer to the immediate question, but I would usually write such a test as:

    if ($inst !~ /lea/i) { # do things }

    and I would always default to interpolation rather than concatenation so my test would look more like:

    if ("$label$inst" !~ /\blea\b/i) { # do things }
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Why does NOT operator on match operator on string concatenation require two pairs of parens?
by tybalt89 (Monsignor) on Nov 24, 2024 at 23:00 UTC

    Appears to be the "If it looks like a function, it IS a function" rule.

    $ perl -MO=Deparse -e'if (not +($label.$inst) =~ /\blea\b/i) {}' unless (($label . $inst) =~ /\blea\b/i) { (); } -e syntax OK
    $ perl -MO=Deparse -e'if (not "$label$inst" =~ /\blea\b/i) {}' unless ("$label$inst" =~ /\blea\b/i) { (); } -e syntax OK

    Alternative

    $ perl -MO=Deparse -e'if ("$label$inst" !~ /\blea\b/i) {}' unless ("$label$inst" =~ /\blea\b/i) { (); } -e syntax OK
Re: Why does NOT operator on match operator on string concatenation require two pairs of parens?
by jwkrahn (Abbot) on Nov 24, 2024 at 22:09 UTC
    $ perl -MO=Deparse -e'if (not $label.$inst =~ /\blea\b/i) {}' unless ($label . $inst =~ /\blea\b/i) { (); } -e syntax OK
    $ perl -MO=Deparse -e'if (not ($label.$inst) =~ /\blea\b/i) {}' if (!($label . $inst) =~ /\blea\b/i) { (); } -e syntax OK
    Naked blocks are fun! -- Randal L. Schwartz, Perl hacker
Re: Why does NOT operator on match operator on string concatenation require two pairs of parens?
by LanX (Saint) on Nov 24, 2024 at 23:18 UTC
    >    (not ($label.$inst) =~ /\blea\b/i)

    Parens break precedence!

    In this case Perl sees an opening bracket for the operand of the not operator.

    Updates

    (emphasis added)

    See perlop#Terms-and-List-Operators-(Leftward)

    "A TERM has the highest precedence in Perl. They include variables, quote and quote-like operators, any expression in parentheses, and any function whose arguments are parenthesized. Actually, there aren't really functions in this sense, just list operators and unary operators behaving as functions because you put parentheses around the arguments. These are all documented in perlfunc"

    see also perlfunc

    "Any function in the list below may be used either with or without parentheses around its arguments. (The syntax descriptions omit the parentheses.) If you use parentheses, the simple but occasionally surprising rule is this: It looks like a function, therefore it is a function, and precedence doesn't matter. Otherwise it's a list operator or unary operator, and precedence does matter."

    FWIW

    If you're confused what Perl is parsing, using B::Deparse can come in handy.

    $ perl -MO=Deparse -e' (not ($label.$inst) =~ /\blea\b/i)' !($label . $inst) =~ /\blea\b/i; -e syntax OK ~ $ ~ $ perl -MO=Deparse,-p -e' (not ($label.$inst) =~ /\blea\b/i)' ((!($label . $inst)) =~ /\blea\b/i); -e syntax OK ~ $

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery