\Q acts differently in s/// and m// operations

Discussion in 'Perl Misc' started by gargoyle, Feb 17, 2005.

  1. gargoyle

    gargoyle Guest

    Consider the following code:

    #!/usr/bin/perl -w
    # NOTE: don't focus on the backslashes, I already know Win32 can
    # use / instead. This is simply a regex+metachar question...

    $old = 'C:\\test\\1\\'; # old parent dir
    $new = 'C:\\test\\2\\'; # new parent dir
    $path = 'C:\\test\\1\\bin\\'; # the path we're renaming
    warn "old=$old, new=$new, path=$path\n";

    warn "----- doing match! -----\n";
    $path =~ /^(\Q$old\E)/; # this matches
    warn "captured \$1 = $1\n";
    $path =~ /^(\Q$new\E)/; # this doesn't
    warn "captured \$1 = $1\n";
    warn "old=$old, new=$new, path=$path\n";

    warn "----- doing substitution! -----\n";
    $path =~ s/^\Q$old\E/\Q$new\E/;
    warn "old=$old, new=$new, path=$path\n";
    __END__

    The output:

    old=C:\test\1\, new=C:\test\2\, path=C:\test\1\bin\
    ----- doing match! -----
    captured $1 = C:\test\1\
    captured $1 = C:\test\1\
    old=C:\test\1\, new=C:\test\2\, path=C:\test\1\bin\
    ----- doing substitution! -----
    old=C:\test\1\, new=C:\test\2\, path=C\:\\test\\2\\bin\

    In the m// operation, the captured output is the original variable, not
    the quotemeta version.

    But in the s/// operation, the output is quoted.

    Why are they behaving differently? And is there a way to get unquoted
    output from the s/// operation, or am I just better off using substr(),
    since after all there's no unquotemeta() function?
     
    gargoyle, Feb 17, 2005
    #1
    1. Advertising

  2. gargoyle

    Bob Walton Guest

    gargoyle wrote:

    ....
    > In the m// operation, the captured output is the original variable, not
    > the quotemeta version.
    >
    > But in the s/// operation, the output is quoted.
    >
    > Why are they behaving differently? And is there a way to get unquoted
    > output from the s/// operation, or am I just better off using substr(),
    > since after all there's no unquotemeta() function?
    >


    Well, the "replacement" in the s/// operator is a *string*, not a
    regexp. And that string is processed per qq(). For that, \Q has
    a different meaning -- all non-word characters following \Q are
    quoted, just as you noted above. In the m// regexp, it is the
    *regexp* characters that are quoted, and not any characters in
    the matched string. You probably should simply dispense with the
    \Q and \E in your replacement string. For details, see:

    perldoc perlop

    particularly the sections on quote and quote-like operators and
    on regexp quote-like operators.

    And there *is* an "unquotemeta" function for a string quoted by
    \Q -- eval(qq(qq/$string/)) should do the trick, I think, as in:

    d:\junk>perl -e "$a=qq(ab\Q~!@#\E~!@#);print eval qq/qq($a)/"
    ab~!@#~!@#
    d:\junk>

    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
     
    Bob Walton, Feb 17, 2005
    #2
    1. Advertising

  3. gargoyle

    gargoyle Guest

    On 2005-02-17, Bob Walton <> wrote:
    > Well, the "replacement" in the s/// operator is a *string*, not a
    > regexp. And that string is processed per qq(). For that, \Q has
    > a different meaning -- all non-word characters following \Q are
    > quoted, just as you noted above.


    Aha! Now I understand. Thanks for clearing that up.

    > And there *is* an "unquotemeta" function for a string quoted by
    > \Q -- eval(qq(qq/$string/)) should do the trick, I think, as in:
    >
    > d:\junk>perl -e "$a=qq(ab\Q~!@#\E~!@#);print eval qq/qq($a)/"
    > ab~!@#~!@#
    > d:\junk>


    Interesting... But I have trouble understanding the impact of several
    levels of quoting and interpolation. It's late though, so I'll re-read
    the perlop manpage tomorrow and see if I can make sense of it.
     
    gargoyle, Feb 17, 2005
    #3
  4. [A complimentary Cc of this posting was sent to
    Bob Walton
    <>], who wrote in article <crTQd.15377$>:
    > Well, the "replacement" in the s/// operator is a *string*, not a
    > regexp. And that string is processed per qq().


    Correct.

    > For that, \Q has
    > a different meaning


    Wrong. \Q has the same meaning everywhere.

    > -- all non-word characters following \Q are quoted


    That's it.

    > In the m// regexp, it is the *regexp* characters that are quoted,
    > and not any characters in the matched string.


    Wrong. But since quoting some characters is a NOOP (e.g., \: matches
    the same as : ), the semantic is somewhat similar to what you wrote -
    which is probably the reason for your confusion.

    > You probably should simply dispense with the \Q and \E in your
    > replacement string.


    Without reading the mind of the author, giving any advice does not
    make sense. I would just note that

    s(REX)(\Q$var);

    is the same as

    $repl = quotemeta $var;
    s(REX)($repl);

    (but the first version is much harder to debug).

    Hope this helps,
    Ilya
     
    Ilya Zakharevich, Feb 17, 2005
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Joe Fallon
    Replies:
    1
    Views:
    427
    Peter Blum
    Feb 15, 2004
  2. Jesus M. Salvo Jr.
    Replies:
    2
    Views:
    4,247
    robert
    Feb 11, 2006
  3. Jim
    Replies:
    2
    Views:
    458
  4. John Kotuby
    Replies:
    3
    Views:
    2,610
    John Kotuby
    Feb 15, 2008
  5. Yahav
    Replies:
    10
    Views:
    224
    Tad McClellan
    Mar 23, 2005
Loading...

Share This Page