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

Hello, I have the following perplexing situation. The "@@" is not being quoted no matter how quote it, i.e. \Q@@ or \@\@ This is the code in question:
$line =~ m|\A(.+)\Q@@/|;
Thanks for the help, Jim

Replies are listed 'Best First'.
Re: regular expression with @@/
by BioLion (Curate) on Dec 07, 2009 at 18:09 UTC

    According to perlretut ( here ):

    The escape sequence \Q ...\E quotes, or protects most non-alphabetic + characters. For instance, 1. $x = "\QThat !^*&%~& cat!"; 2. $x =~ /\Q!^*&%~&\E/; # check for rough language It does not protect $ or @ , so that variables can still be substitute +d.
    And perl.com says :
    You cannot include a literal $ or @ within a \Q sequence. An unescaped $ or @ interpolates the corresponding variable, while escaping will cause the literal string \$ to be matched. You'll need to write something like m/\Quser\E\@\Qhost/.
    So, escaping should work :
    use warnings; use strict; print "Yes!\n" if ( '$@' =~ m|\$\@| ); # prints "Yes!"
    So maybe your regex isn't what you think - try a little debugging :
    use warnings; use strict; my $string = '@@@'; if ( $string =~ m|\$\@| ){ print "Yes!\n"; } else { print "\'$string\' did not match...\n"; } # prints "'@@@' did not match..."
    HTH

    Update: Hmmm... damn slow typing... kennethk may have won the battle, but next time...(or not)!

    Just a something something...

      Actually, in this particular case, it should work with and without quoting, because /@@/ doesn't interpolate anything (as opposed to /@@x/ or /\Q@@x\E/, for example).

      #!/usr/bin/perl use warnings; use strict; $_ = 'foo@@bar'; print "matched\n" if /@@/; print "matched\n" if /\Q@@\E/; print "matched\n" if /\@\@/; __END__ matched matched matched

      Update: maybe a better (anchored) check, avoiding the potential gotcha of matching against a single-@ pattern:

      #!/usr/bin/perl use warnings; $_ = '@@'; print "1 matched\n" if /^@@\z/; print "2 matched\n" if /^\Q@@\E\z/; print "3 matched\n" if /^\@\@\z/; print "4 matched\n" if /^\Q@@x\E\z/; # doesn't match, because @x is be +ing interpolated print "5 matched\n" if /^@\@x\z/; # doesn't match, because there is + no 'x' in the string __END__ Possible unintended interpolation of @x in string at ./811585.pl line +10. Name "main::x" used only once: possible typo at ./811585.pl line 10. 1 matched 2 matched 3 matched

        Good call - as usual - I guess I more wanted to make the point that adding in some debugging is always useful, just so if things *don't* match, you can see exactly what they are, and tell if it is your input or your regex that isn't what you think...

        Just a something something...
Re: regular expression with @@/
by kennethk (Abbot) on Dec 07, 2009 at 18:01 UTC
    \@ should work. Are you sure $line contains what you think it does? Perhaps if you gave us a little more code?

    #!/usr/bin/perl use strict; use warnings; my $line = 'sometext@@sometext'; if ($line =~ m|\@\@|) { print "success!\n"; }

    I'm willing to bet that what is going on is described in Quote and Quote like Operators.

      Thank you all for the help. This works as expected so I will dig deeper in my code.
      use warnings; use strict; my $line = 'cfperfexh.prof@@/main/1'; print "Success! -- $1\n" if $line =~ /\A(.+)\@\@/; exit 0;
        You need -e or -d, not -f
      here is my revised code: (with parts edited out)
      use warnings; use strict; my $file = shift or die "need filename from command-line"; open FH, '<', $file or die "could not open $file for reading: $!"; while( defined( my $line = <FH> )) { chomp $line; $line =~ m|\@\@/| && -f $line and do { ( $filename ) = $line =~ m|\A(.+)\@\@/|; chomp $line; print "$line -- "; next; }; }
        What file system are you on that / is a valid character in a file name? You presumably expect a regular file (-f) to end in @@/, which is presumably where your tests are failing. Perhaps this is a relative vs. absolute path issue?
Re: regular expression with @@/
by keszler (Priest) on Dec 07, 2009 at 18:08 UTC
    Interesting!
    [keszler@tek src]# perl -le ' $x = "asdfXXsadf"; print "match" if $x =~ /\QXX\E/; ' match [keszler@tek src]# perl -le ' $x = "asdf@@sadf"; print "match" if $x =~ /@@/; ' [keszler@tek src]# perl -le ' $x = "asdf@@sadf"; print "match" if $x =~ /\Q@@\E/; ' [keszler@tek src]# perl -le ' $x = "asdf@@sadf"; print "match" if $x =~ /\@\@/; ' [keszler@tek src]# perl -le ' $x = "asdf@@sadf"; print "match" if $x =~ /@/; ' match [keszler@tek src]# perl -le ' $x = "asdf@@sadf"; print "match" if $x =~ /@{2}/; ' match
      $ perl -wle ' $x = "asdf@@sadf"; print "match" if $x =~ /\Q@@\E/; ' Possible unintended interpolation of @sadf in string at -e line 2. Name "main::sadf" used only once: possible typo at -e line 2.

      :)

Re: regular expression with @@/
by ikegami (Patriarch) on Dec 07, 2009 at 18:27 UTC

    Your code is fine. Both \Q and \ will escape @.

    $ perl -le'print q{@@} =~ m|\A\Q@@\E\z| ? "match" : "no match"' match $ perl -le'print q{@@} =~ m|\A\@\@\z| ? "match" : "no match"' match

    Are you sure your input is what you think it is?

    Update: Turns out that \Q only helps insofar as @@ doesn't get interpolated to begin with.

      Both \Q and \ will escape @

      No, \Q doesn't:

      $ perl -wle'print q{@@x} =~ m|\A\Q@@x\E\z| ? "match" : "no match"' Possible unintended interpolation of @x in string at -e line 1. Name "main::x" used only once: possible typo at -e line 1. no match $ perl -wle'print q{@@x} =~ m|\A@\@x\z| ? "match" : "no match"' match
        ah, interesting!
        $ perl -le'@@=qw( a b ); print qr|\Q@@|' (?-xism:\@\@) $ perl -le'@@=qw( a b ); print qr|@@|' (?-xism:@@) $ perl -le'@a=qw( a b ); print qr|\Q@a|' (?-xism:a\ b)

        I knew something was hinky with what I had posted.

Re: regular expression with @@/
by JavaFan (Canon) on Dec 07, 2009 at 22:08 UTC
    There's no need to quote. Regular expressions don't interpolate arrays where the name is a punctuation symbol:
    say qr|\A(.+)\Q@@/|; __END__ (?-xism:\A(.+)\@\@\/)
    But in general, if you use single quotes as delimiter, no interpolation will happen:
    my @a = ("foo"); say "foo" =~ m |@a| ? 'Found "foo"' : 'Did not find "foo"'; say "foo" =~ m '@a' ? 'Found "foo"' : 'Did not find "foo"'; say 'bar@a' =~ m |@a| ? 'Found "@a"' : 'Did not find "@a"'; say 'bar@a' =~ m '@a' ? 'Found "@a"' : 'Did not find "@a"'; __END__ Found "foo" Did not find "foo" Did not find "@a" Found "@a"
Re: regular expression with @@/
by JadeNB (Chaplain) on Dec 11, 2009 at 09:49 UTC
    I think your (very interesting!) problem has been solved several times already—the main points being that
    • you don't need to escape @@ in the regex (but would need to if it were followed by some alphabetic character);
    • if you did, then \Q usually wouldn't do it (but seems to do it in this case, because there's no interpolation going on), but single-quote delimiters instead of ' would;
    • and, anyway,
    • probably the problem is that your input doesn't actually contain @@ as you think it does (for example, "a@@b" is actually a@ concatenated with the stringification of @b)
    —so I'll just point out one thing that no one seems to have mentioned, which is that \Q/\E are a pair, and must should be used as such. Your sample code has only a \Q, although Perl seems forgivingly to assume the \E:
    $ perl -E 'say my $rx = qr|\A(.+)\Q@@/|;' (?-xism:\A(.+)\@\@\/)
    You may also be interested in the function, quotemeta, underlying the escape, which works fine on @.