开发者

Perl map block local variable usage

This code compiles a set by way of hash keys of the unique basename stubs in a set of paths.

%stubs = map { $f=basename $_; $f =~ /^([A-Za-z]+[0-9]+)\./ ; $1=>() } @pathlist;

Why do I need the $f references here? I thought I'd be ok with:

%stubs = map { basename; /^([A-Za-z]+[0-9]+)\./; $1=>() } @pathlist;

But I get no match. Am I not permitted to modify $_ in the map block?

For those wondering what the code is doing:

For each $path (@pathlist), it's getting the basename, matching the first letter-number sequence, and then returning the first bracket match as the key on an empty list value. Example:

/some/dir/foo123.adfjijoi开发者_如何学Pythonjb
/some/dir/foo123.oibhobihe
/some/dir/bar789.popjpoj

returns

foo123 => ()
bar789 => ()

After which I use the keys of the map as the set of values so process.


basename does not default to acting on $_. But you can match against its return value instead of using $f:

%stubs = map { basename($_) =~ /^([A-Za-z]+[0-9]+)\./; $1 => undef } @pathlist;

Note that () in a list doesn't produce an element, it just flattens to nothing; you have to provide a value, even if only undef. With $1 => (), map iterations would alternate producing a key and a value for %stubs.

It's good to always check that your regex succeed before using $1:

%stubs = map { basename($_) =~ /^([A-Za-z]+[0-9]+)\./ ? ($1 => undef) : () } @pathlist;

though if you don't mind the hash values being the empty string instead of undef, you can just make the regex match return the desired list:

%stubs = map { basename($_) =~ /^([A-Za-z]+[0-9]+)()\./ } @pathlist;


In map and grep, $_ is an alias for the values in the array. If you modify them, you actually modify the values in the array. This is probably not what you want and probably what is going wrong, but to debug print keys %stubs and @pathlist afterwards in both cases and let us know what it says.

Also: File::Basename's basename does not implicitly work on $_. It generates an error for me.

#!/usr/bin/perl
use feature say;
use File::Basename;

@pathlist=("/some/dir/foo123.adfjijoijb","/some/dir/foo123.oibhobihe","/some/dir/bar789.popjpoj");
%stubs1 = map { $f=basename $_; $f =~ /^([A-Za-z]+[0-9]+)\./ ; $1=>() } @pathlist;
say join(',',keys %stubs1);
say "---";
say join(',',@pathlist);
say "---";

%stubs = map { $_=basename $_; /^([A-Za-z]+[0-9]+)\./; $1=>() } @pathlist;
say join(',',keys %stubs);
say "---";
say join(',',@pathlist);
say "---";

%stubs = map {basename; /^([A-Za-z]+[0-9]+)\./; $1=>() } @pathlist;


Alternate implementation:

my %stubs =
   map { $_ => undef }
   map { basename($_) =~ /^([A-Za-z]+[0-9]+)\./ }
   @pathlist;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜