所以我试图根据 foreach 内的正则表达式创建数组的哈希值。
我得到了一些文件路径,它们的格式如下:
longfilepath/name.action.gz
所以基本上会有同名但不同操作的文件,所以我想用作为操作数组的名称键创建一个哈希。我显然做错了什么,因为当我运行代码时不断收到此错误:
Not an ARRAY reference at ....the file I'm writing in
我不明白,因为我正在检查它是否已设置,以及是否未将其声明为数组。我还在习惯 Perl,所以我猜我的问题很简单。
我还应该说,我已经验证我的正则表达式正确生成了“名称”和“操作”字符串,因此问题肯定出在我的 foreach 中;
感谢您的帮助。 :)
我的代码是这样的。
my %my_hash;
my $file_paths = glom("/this/is/mypath/*.*\.gz");
foreach my $path (@$bdr_paths){
$path =~ m"\/([^\/\.]+)\.([^\.]+)\.gz";
print STDERR "=>".Dumper($1)."\n\r";
print STDERR "=>".Dumper($2)."\n\r";
#add the entity type to a hash with the recipe as the key
if($my_hash{$1})
{
push($my_hash{$1}, $2);
}
else
{
$my_hash{$1} = ($2);
}
}
最佳答案
这是glob
,而不是glom
。在 glob 表达式中,句点不是元字符。 → glob '/this/is/mypath/*.gz'
。
使用备用正则表达式分隔符的全部原因是为了避免不必要的转义。正斜杠不是正则表达式元字符,而是分隔符。在字符类内部,许多运算符失去了它们的特殊性;无需逃避该时期。因此 m!/([^/.]+)\.([^.]+)\.gz!
.
不要将 \n\r
附加到输出中。 ① Dumper
函数已经添加了换行符。 ② 如果您使用的操作系统需要 CRLF,则使用 :crlf
PerlIO 层,它将所有 \n
转换为 CRLF。您可以通过 binmode STDOUT, ':crlf'
添加层。 ③ 如果您正在进行网络,最好指定您想要发出的确切字节,例如\x0A\x0D
或 \012\015
。 (但在这种情况下,还要删除所有 PerlIO 层)。
使用引用作为 push
的第一个参数在 v5.14 之前的 perls 上不起作用。
不要手动检查您是否在哈希中填充了槽;如果它是 undef
并用作 arrayref,则会自动创建一个数组引用。这被称为自动生存。当然,这需要您执行此取消引用(并跳过 push
的缩写形式)。
在 Perl 中,括号仅排序优先级,并在用于赋值的 LHS 时创建列表上下文。他们不创建数组。要创建匿名数组引用,请使用括号:[$var]
。像你这样使用括号是没有用的; $x = $y
和 $y = ($y)
完全相同。
所以你要么想要
push @{ $my_hash{$1} }, $2;
或
if ($my_hash{$1}) {
push $my_hash{$1}, $2;
} else {
$my_hash{$1} = [$2];
}
编辑:我忽略了三件事。
如果在标量上下文中使用glob
,它将变成一个迭代器。这通常是不需要的,除非以 while(my $path = glob(...)) { ... }
之类的方式使用。否则更难以确保迭代器已耗尽。相反,在列表上下文中使用 glob
一次性获取所有匹配项:my @paths = glob(...)
。
$bdr_paths
来自哪里?里面是什么?
始终检查正则表达式是否确实匹配。这可以避免细微的错误,因为捕获 $1
等会保留其值,直到下一次成功匹配。
关于regex - 基于正则表达式在 Perl 中的 foreach 中制作数组的动态哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17979567/