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

Reading a Perl source, I encountered this line:
($Z = $0) =~ s~.*/~~;

I guess this saves in $Z the name of the script being executed, but it's not clear to me why it uses tildes instead of slashes.
Better, I've never seen using tildes instead of slashes, and I didn't know that such practice is possible.
Am I missing something?
Thank you

Replies are listed 'Best First'.
Re: quite weird regexp
by davorg (Chancellor) on Nov 30, 2000 at 14:35 UTC

    You can use any non-alphanumeric character as the separator in a s/// or m// operator. This allows you to choose a separator which doesn't clash with the data in the string.

    In this case, if you used the 'traditional' slash as the delimiter then you'd need to escape the slash that appears in the regex. By changing the separator, you don't need to do that.

    You can also use 'bracketing' characters, like (, [, < or {. In that case you need to use the opposite character at the other end, like this:

    s[something][else];

    This is all explained in perldoc perlop.

    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

      What perlop doesn't tell you is that, if you put a space after the operator name, you can use alphanumeric characters as delimiters. To use the current example: ($Z = $0) =~ s z.*/zz; I also made use of this in homer.pl, with m mmm, Donuts. But please don't do this in production code! :)

      To be precise (citing from perlop manpage):

      • Whitespace is not a valid delimiter, and there are additional semantics associated with single quotes:
        s/PATTERN/REPLACEMENT/egimosx [ ... snip ...] Any non-alphanumeric, non-whitespace delimiter may replace the slashes. If single quotes are used, no interpretation is done on the replacement string (the /e modifier overrides this, however). Unlike Perl 4, Perl 5 treats backticks as normal delimiters; the replacement text is not evaluated as a command. If the PATTERN is delimited by bracketing quotes, the REPLACEMENT has its own pair of quotes, which may or may not be bracketing quotes, e.g., s(foo)(bar) or s<foo>/bar/. A /e will cause the replacement portion to be interpreted as a full-fledged Perl expression and eval()ed right then and there. It is, however, syntax checked at compile-time.
      • with m//, you also want to watch out not to use '?' as the delimiter, as this has a different meaning:
        ?PATTERN? This is just like the /pattern/ search, except that it matches only once between calls to the reset() operator. This is a useful optimization when you want to see only the first occurrence of something in each file of a set of files, for instance. Only ?? patterns local to the current package are reset. [ ... snip ...] m/PATTERN/cgimosx /PATTERN/cgimosx [ ... snip ...] If "/" is the delimiter then the initial m is optional. With the m you can use any pair of non- alphanumeric, non-whitespace characters as delimiters. This is particularly useful for matching Unix path names that contain "/", to avoid LTS (leaning toothpick syndrome). If "?" is the delimiter, then the match-only-once rule of ?PATTERN? applies. If "'" is the delimiter, no variable interpolation is performed on the PATTERN.

        This is all explained in perldoc perlop (there is no "perlops" manpage).

        Christian Lemburg
        Brainbench MVP for Perl
        http://www.brainbench.com

      Thank you very much.
      (Alas, perhaps I count from 1 to 10 too quickly :) )
Re: quite weird regexp
by mirod (Canon) on Nov 30, 2000 at 17:36 UTC

    So let's see what this does:

    $z= $0; # store the name of the script in $z $z=~ s{.* # anything, greedy match / # then a / (the last one in $z as the match is greedy) }{}x; # removed

    So this snippet just returns the basename of the script.

    And as you see you can also use brackets like { } as delimiters, and the x modifier lets you comment the regexp.

Re: quite weird regexp
by cadfael (Friar) on Nov 30, 2000 at 20:16 UTC
    There is a real good reason why there is an option for changing the delimiter in pattern substitution. Witness the following code I used to alter URLS that needed to appear in a text field in a flatfile database:
    while(<>){ #take input from STDIN s/\/\//\\\/\\\//g; print STDOUT; }
    Why? Because the designers of this flatfile database decreed that "//" would be interpreted as the beginning of a comment, thus causing everything after "http://" to be lost. So I escaped those particular forward slashes using s///; It looks atrocious, but it did the job.

    Using an alternate delimiter wouldn't eliminate the need for all the forward and back slashes, but at least it would show me (or another trying to decipher the above atrocity) where the expression was delimited.

    -----
    "Computeri non cogitant, ergo non sunt"