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

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

Below is one line in Win32\TieRegistry.pm .I can't understand it.

grep( s#$#$RegObj->{DELIM}#, @{ $RegObj->{MEMBERS}= [ @{$RegObj->{SUBKEYS}} ] } );

what does it mean for grep function's 2 argument? what on earth "s#$#"mean? Thanks!

Replies are listed 'Best First'.
Re: can understand one line of code
by BrowserUk (Patriarch) on Dec 19, 2012 at 15:24 UTC

    Break it down:

    1. grep( expression, @{ ... } )
    2. The expression  s#$#$RegObj->{DELIM}#

      start with 's', so it is a substitution.

      The #s are delimiters so the two sides are: $ and $RegObj->{DELIM}

      So it is substituting the module defined delimiter for any '$'s every end of line.

    3. The array: @{ $RegObj->{MEMBERS}= [ @{$RegObj->{SUBKEYS}} ] }

      Contains an assignment: $RegObj->{MEMBERS}= [ @{$RegObj->{SUBKEYS}} ]

      It copies the array of subkeys : @{ $RegObj->{SUBKEYS} } into an anonymous array [ ... ]

      And assigns its reference to $RegObj->{MEMBERS} = ...

      Then it dereferences that to supply the subkeys to grep.

    Thus, that one line is equivalent to:

    my @temp = @{ $RegObj->{SUBKEYS} }; $RegObj->{MEMBERS} = \@temp; grep s[$][$RegObj->{DELIM}], @temp;

    Without the need for @temp; but less efficient.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

Re: can understand one line of code
by toolic (Bishop) on Dec 19, 2012 at 15:23 UTC
Re: can understand one line of code
by tobyink (Canon) on Dec 19, 2012 at 15:22 UTC

    It's quite obscurely written, but, it's roughly equivalent to:

    my @results; my @tmp_array = @{ $RegObj->{SUBKEYS} }; $RegObj->{MEMBERS} = \@tmp_array; for my $member (@{ $RegObj->{MEMBERS} }) { next unless $member =~ /\$/; $member =~ s/\$/$RegObj->{DELIM}/; push @results, $member; } @results;
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: can understand one line of code
by roboticus (Chancellor) on Dec 19, 2012 at 15:39 UTC

    anacondy_wly:

    The s#xxx#yyy# is just an alternate form of s/xxx/yyyx. With the s and </c>m</c> operators, you can specify an alternate set of delimiters for your regex. It's often used to make an expression easier to read--for example, if you're altering strings with slashes in them (think directory paths), then you'd need to prefix each '/' with a '\' inside your regular expression if you used the typical '/' delimiter. If you choose a different delimiter, though, it can be easier to read. Note: You can also used curly braces, too. These three expressions are identical:

    $t =~ s/\/home\/roboticus\/tmp/\/home\/postgresql\/tmp/; $t =~ s{/home/roboticus/tmp}{/home/postgresql/tmp}; $t =~ s#/home/roboticus/tmp#/home/postgresql/tmp#;

    So since the grep statement gets a list of aliases, the statement is first altering the value, then checking whether it should be included in the output list. A trivial example:

    $ cat t.pl #!/usr/bin/perl my @a = qw(apple banana cherry durian); my @b = grep { s#(a.)+#x#g; m/x/ } @a; print join(", ", @b), "\n"; $ perl t.pl xple, bxa, durix

    Finally, the statement doesn't look like it's syntactically correct, but as I understand it the grep command is doing another transformation: It seems to be setting the MEMBERS item to the number of an array ref of a list of the SUBKEYS. Then, since grep evaluates each element in scalar context, the grep statement keeps the item if and only if there are any SUBKEYS. However, $ isn't a variable, so the first bit of the code block looks incorrect. Secondly, since nothing changes $RegObj, I don't see what good is going to happen: it seems to me that either all elements would be retained in the list, or none of them would.

    If no objects are supposed to be retained, then I'd simply use a for loop to process the items. If all items should be retained, then I'd replace the statement with a map statement.

    Just my $0.02.

    Update: Jiminy, I'm slow. Three answers before I replied, and they show that I goofed. I also obviously got it a bit wrong. (That's what I get for not testing.) I was expecting a variable expansion in the match portion of the regex. (I don't know *why* I expected it, as '$' is the 'end of line' match character. Perhaps I was thrown off by the use of something that looked like a variable name on the right side.) So anyway, I've stricken the bit that's patently incorrect, and underlined a bit of text I inserted to partially correct it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      OK. I understand. Thank all of you for the quick, precise and clear answer. I read everyone's answer carefully. All are very great! Thanks!