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

I've a simple example here, perhaps somebody could explain the difference, 'cos I'm at a loss to...

perl -e '$a="MIN.(NERR_VOL2)"; $b="$a" ; $x = ( qq/$a/ =~ qq/$b/ ) ; p +rint "$a == $b ? $x \n" ;'

>>> gives ;

MIN.(NERR_VOL2) == MIN.(NERR_VOL2) ?

BUT...

perl -e '$a="MIN.(NERR_VOL2)"; $b="$a" ; $x = ( qq/$a/ eq qq/$b/ ) ; p +rint "$a == $b ? $x \n" ;'

>>> gives ;

MIN.(NERR_VOL2) == MIN.(NERR_VOL2) ? 1

Why does =~ fail to match but eq does match ?

Replies are listed 'Best First'.
Re: Matching quoted variables. Cant make it work..
by Fletch (Bishop) on Mar 16, 2006 at 02:22 UTC

    Because =~ is the regular expression binding operator, not string equals (which is what eq). It matches the regex on its right hand side against the scalar on the left. Since you've given it a string with regular expression metacharacters in it which doesn't match itself it fails. See perlretut and perlre.

    (Once you've read that try and figure out what would happen if you changed it to $b = "\Q$a\E" instead . . .)

Re: Matching quoted variables. Cant make it work..
by roboticus (Chancellor) on Mar 16, 2006 at 02:36 UTC
    John--

    The eq operator looks for an exact match of the left and right value, whilst the =~ operator checks to see if the string on the left contains the regular expression on the right side.

    The problem is that the string you're using contains characters in it that have special meaning when they're inside a regular expression. In this case, these are the parenthesis. For your regular expression argument, try escaping the special characters, like so:
    perl -e '$a="MIN.(NERR_VOL2)"; $b="MIN.\(NERR_VOL2\)" ; $x = ( qq/$a/ +=~ qq/$b/ ) ; print "$a == $b ? $x \n" ;'
    You'll want to read the 'perlre' documentation to see what's going on here.

    Note 1: There's another character in the expression that has special meaning in your regular expression, but it didn't hurt you in this case.

    Note 2: Another thing: You should never assign a variable like so:
    $b = "$a";
    You're telling perl to create a string, and since it has an expression inside the string, you're telling it to interpolate the value. The end result is that you're asking Perl to do a lot more work to get the result you really want:
    $b = $a;
    which tells Perl to simply copy the value of $a into $b.

    --roboticus
      You should never assign a variable like so:

      Well, not necessarily "never". In general for 99.99999% of the cases you don't want the extra quotes; however there's times when you may want to explicitly "stringify" something (say an object with an overloaded q// method). They're few and far between, but not never ever.</pedant>

        Fletch--

        I'm often a pedant myself, so thanks for the correction. I don't quite follow what you mean, though. Could you provide or point me to a trivial example, perhaps?

        --roboticus

      BTW although the '.' meta-character doesn't hurt you in this case, it does mean you are risking a match-positive when you would expect a match negative

      e.g.

      $a = 'hello.world'; $b = 'helloxworld'; print "matched" if $b =~ /$a/;

      You will get a match in the above example (because '.' means any single character in a regex).

      Tom Melly, tom@tomandlu.co.uk
Re: Matching quoted variables. Cant make it work..
by japhy (Canon) on Mar 16, 2006 at 17:54 UTC
    Because there are characters in $b that are interpreted differently when used in a regex. The ".", "(", and ")" are such characters. You'd have to do $a =~ /\Q$b\E/ to get it work, or else use quotemeta(). If you want to see if they're equal, though, use 'eq'. If you want to see if one contains the other, use index(). If you want to match a pattern, THEN use a regex.

    Can I ask why you're quoting $a and $b?


    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      I'm using variables because I'm doing a context based search for a string in a file. This string changes at different places in the file.

      As you rightly pointed out.. quotemeta($a) is what I was really looking for, but missed it. Too many languages in my head.. F77,lisp,skill,c,tcl,perl,csh,ksh.......etc etc. I knew I wanted to 'quote' the contents of the variable to prevent regex interpretation, but didn't see how.

      And yes, everyone is correct, that in the example I chose to show, the matching is redundant and 'eq' or index() is a better choice. But once I got stuck on the problem I wanted to understand the generalities of quoting & regex with variables for future use.

      Thanks to everyone, I can see clearly now ...

Re: Matching quoted variables. Cant make it work..
by ikegami (Patriarch) on Mar 16, 2006 at 18:10 UTC

    Let's go into details...

    qq/$a/ =~ qq/$b/ is equivalent to
    "$a" =~ "$b" (because qq// and "" are the same quoting operator), and to
    $a =~ "$b" (because a match already forces the stringification of its left hand side), and to
    $a =~ $b (because a match already forces the stringification of its right hand side if it's not a compiled regexp), and to
    $a =~ /$b/ (because strings on the right hand side of a match are treated as regexp), and to
    $a =~ /MIN.(NERR_VOL2)/ (because we know the value of $b).

    But remember that ., ( and ) are special characters in regexps.

    If you wanted to check for equality, you want
    $a =~ /^\Q$b\E\z/
    or the faster
    $a eq $b

    If you wanted to check for "$b is in $a", you want
    $a =~ /\Q$b/
    or the faster
    index($a, $b) >= 0

    By the way,
    qq/$a/ eq qq/$b/ is equivalent to
    "$a" eq "$b" (because qq// and "" are the same quoting operator), and to
    $a eq $b (because eq already forces stringification of its args).

Re: Matching quoted variables. Cant make it work..
by Anonymous Monk on Mar 16, 2006 at 02:20 UTC

    Please allow me to rewrite your examples in a way that maintains rough equivalence whilst hopefully making the differences more apparent.

    { my $a = "MIN.(NERR_VOL2)"; my $b = $a; print "matches" if $a =~ m/$b/; }
    { my $a = "MIN.(NERR_VOL2)"; my $b = $a; print "equals" if $a eq $b; }
Re: Matching quoted variables. Cant make it work..
by swampyankee (Parson) on Mar 17, 2006 at 20:06 UTC

    A couple of quibbles to start:

    • Please surround your code samples with <code>..>/code< tokens; this makes it easier to read
    • Please do not use $a and $b as variable names; these are special

    When I run you first case through the debugger, I get 'empty array' as the result of
    $x =&nbsp;(qq/$a/ =~ qq/$b/)
    I suspect that this is a more appropriate way of writing your use of the regex:

    ($n = $a) =~ /$b/;

    With the proviso (I'm repeating myself) that $a and $b should not be used as variable names except in sort { $a <=> $b} @array;

    emc

    " When in doubt, use brute force." — Ken Thompson

    Reparented from duplicate thread Reaped: Matching quoted variables. Cant make it work.. by Arunbear

Re: Matching quoted variables. Cant make it work..
by johntweed (Initiate) on Mar 16, 2006 at 18:15 UTC
    Thanks for the feedback, but I think that my main problem is with understanding the action of the quoting (or lack of). Some replies did state that the meta characters of the string prevent the regex from matching. I can see that is stopping the match. But what level of quoting is necessary here to prevent the meta characters from messing up the match ?

    So the real issue, now, in my mind is not so much 'how regex works' but how would I use quoting to make the regex ignore the possibility that the input variables might contain a meta character, since this example is just the essence of problem and not my complete code.

      A previous suggestion to use

      "\Q$a\E"

      is the easiest way to avoid these kind of problems. If you want to inlclude a variable that may contain meta-characters, then \Q forces the escaping of meta-characters (i.e. puts '\' before each one). \E turns escaping off. Play with it.

      Hope that helps.

      Tom Melly, tom@tomandlu.co.uk