http://www.perlmonks.org?node_id=184979

While cruising through the Perl source, I found this delightful line of code in toke.c, in the S_scan_str() function:
if (term && (tmps = strchr("([{< )]}> )]}>", term))) term = tmps[5];
It blew my mind. What it does is find the matching delimiter for a q// string if the delimiter happens to be one of those specific characters.

Here's the quiz. First, how does it work? Second, why is )]}> repeated?

_____________________________________________________
Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Replies are listed 'Best First'.
Re: Source Divers: string delimiters
by mojotoad (Monsignor) on Jul 24, 2002 at 19:40 UTC
    Wow, life outside of hash-think.

    I did a double take when first looking at that code -- it was immediately obvious that it was a mechanism to summon the associated balanced character for a terminator.

    However, there is an identity function built in, implying that you can simply use two "closing" terminators. Which means stuff like this is correct perl:

    my $str = qw)You can quote me on this);

    It sure looks odd, but doesn't seem to break anything. Just goes to show you learn something every day.

    Matt

    Update: Hmmm, I forgot about the list behavior of said quoting construct. Here are some more clear examples:

    @words = qw)You can quote me on this); $str = q)You can quote me on this);
      I expect we'll be seeing this in JAPHs and obfus pretty soon, now that it's been brought to the general attention.
        My current sig uses this "trick".

        _____________________________________________________
        Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

        And besides japhy's sig, many other obfuscations have made use of this a long time ago - just dig around the section.

        Makeshifts last the longest.

Re: Source Divers: string delimiters
by jackdied (Monk) on Jul 24, 2002 at 19:34 UTC
    In a DWIM way, perl requires a closing brace/paren/etc if it is an open/close kinda symbol. If it is plain like '/' or a closer like '}' then it expects the same symbol as the opener and closer. The closer is always at tmps{5}, if it is an opener the compliment is a closer. Otherwise, it is another of the same symbol.

    Cool code

Re: Source Divers: string delimiters
by Abigail-II (Bishop) on Jul 25, 2002 at 09:45 UTC
    strchr locates the first occurance of the second argument (a character) in its first argument (a string). It's returned as a pointer. So, if term = '[' it returns a pointer to the [ in "([{< )]}> )]}>". 5 characters later in the string, you find the closing delimiter. The sequence )]}> is repeated because they are valid opening delimiters as well.

    Here's a followup question: why does the string have spaces in it?

    Abigail

      Whitespace is no longer a valid delimiter (older Perls allowed it), and there are already measures taken to advance past the whitespace. In addition, " " is not a special case character like the brackets are. Therefore, I'll hazard a guess and say they're in there for readability. And because 5 is such a better offset than 4.

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Source Divers: string delimiters
by cybear (Monk) on Jul 25, 2002 at 12:06 UTC
    I hate to admit this but, I don't get it.

    Well... I didn't get it, the explinations from Y'all have helped a lot.
    P.S. - how much free time have you got japhy?

Re: Source Divers: string delimiters
by PrakashK (Pilgrim) on Jul 26, 2002 at 20:29 UTC
    While crusing through the Perl source, ...
    Am I the only one who read the above as: While cursing through the Perl source, ... ?

    ;-)
    /prakash