【问题标题】:Perl map block local variable usagePerl 映射块局部变量的使用
【发布时间】:2011-05-19 07:19:25
【问题描述】:

此代码通过一组路径中唯一基名存根的哈希键编译一组。

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

为什么我需要$f 引用?我以为我可以接受:

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

但我没有匹配。我不允许在地图块中修改 $_ 吗?



对于那些想知道代码在做什么的人:

对于每个 $path (@pathlist),它获取基本名称,匹配第一个字母数字序列,然后返回第一个括号匹配作为空列表值的键。示例:

/some/dir/foo123.adfjijoijb
/some/dir/foo123.oibhobihe
/some/dir/bar789.popjpoj

返回

foo123 => ()
bar789 => ()

之后,我使用地图的键作为值集进行处理。

【问题讨论】:

  • 我想知道 $1=>() 构造——它返回 1 元素列表,并且您分配给 hash 所以您必须有一个偶数大小的列表。试试看:perl -MData::Dumper -we 'my %hash = map { /(\d+)/; $1 => () } 1..5; print Dumper(\%hash)'

标签: perl map implicit local-variables


【解决方案1】:

basename 不默认作用于$_。但是你可以匹配它的返回值而不是使用 $f:

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

请注意,列表中的 () 不会产生元素,它只是变平为空;你必须提供一个值,即使只有 undef。使用$1 => (),map 迭代将交替生成 %stubs 的键和值。

最好在使用 $1 之前检查您的正则表达式是否成功:

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

如果你不介意哈希值是空字符串而不是 undef,你可以让正则表达式匹配返回所需的列表:

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

【讨论】:

  • @Dallaylaen:我突然想到你也可以做 undef:/(something)()??/
  • 优秀的答案。哈希只是为了产生集合行为,即获得唯一的存根。对于哪些函数默认作用于 $_ 而哪些不作用,有什么规则吗?
  • @Phil H:大多数库函数(与内置函数相反)不默认为 $_ (尽管有一些这样做);对于内置函数,默认为 $_ 是有意义的(尽管有些是最近才在 5.10 中使用的:readpipe、unpack 和 mkdir)
  • 为了进一步解释为什么你应该检查正则表达式是否成功,考虑如果它不成功会发生什么:一个正则表达式匹配设置全局$1,如果正则表达式找不到匹配,$1仍将包含上一场比赛的结果!
  • perl -E '@a = qw/hi bye/; foreach (@a) { /(h.*)/; push @b, $1; } say for @b;' 给出:hi\nhi\n
【解决方案2】:

在 map 和 grep 中,$_ 是数组中值的别名。如果你修改它们,你实际上修改了数组中的值。这可能不是您想要的,也可能是出了什么问题,但是在这两种情况下都调试打印键 %stubs 和 @pathlist 并让我们知道它说了什么。

另外:File::Basename 的 basename 不会隐式地作用于 $_。它会为我生成一个错误。

#!/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;

【讨论】:

  • 啊,我忘了 $_ 是别名。在这种情况下,@pathlist 无论如何都是一次性列表,这并不重要。
【解决方案3】:

替代实现:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2019-07-26
    • 1970-01-01
    • 2018-11-21
    相关资源
    最近更新 更多