如何在Perl的foreach
循环内第二次从文件句柄读取?
foreach $a (@b){
while(my $line = <IN>){
if($line = /$a/){
print $line;
}
}
}
以上代码未处理列表@b
中的第二个元素。如何使其成为可能?
答案 0 :(得分:5)
您的内部循环while(my $line = <IN>)
从IN
句柄中提取行,直到到达文件末尾为止。
当外部循环foreach $a (@b)
尝试再次从IN
读取时,它仍在文件末尾。 foreach
循环的第一次迭代消耗了文件中的所有行,而其他迭代则没有任何内容。
有几种方法可以解决此问题:
Seek回到IN
的开头,然后尝试再次读取它:
foreach $a (@b){
seek IN, 0, 0
or die "Cannot seek(): $!";
while (my $line = <IN>) {
...
}
}
但是,这仅适用于真实文件,不适用于管道,套接字或终端。
将整个文件读入内存,然后遍历普通数组:
my @lines = <IN>;
foreach $a (@b){
foreach my $line (@lines) {
...
}
}
但是,如果文件很大,则会占用大量内存。
切换两个循环的顺序:
while (my $line = <IN>) {
foreach $a (@b) {
...
}
}
这是我的最爱。现在,您只需要从文件中读取一次。 @b
已经在内存中,因此您可以根据需要对其进行多次迭代。
旁注:
IN
之类的裸字文件句柄。普通变量(例如$IN
)在各个方面都优越得多。$a
或$b
的变量。它们有点特殊,因为Perl在sort
中使用了它们。< >
。它很奇怪地重载(根据您使用的确切语法,它可能表示readline
或glob
),并且不是很直观。使用readline
意味着永远不会有语法上的歧义,即使没有Perl经验的程序员也无法弄清楚它的作用。有了这些更改:
while (my $line = readline $IN) {
foreach my $re (@regexes) {
if ($line =~ /$re/) {
print $line;
}
}
}
答案 1 :(得分:2)
您在edit
循环中进行读取,直到文件句柄用尽(到达文件while
的结尾)为止。
如果您不关闭并重新打开文件句柄,则在外循环的第二次迭代中将不再读取该文件句柄。
如果从文件句柄读取的数据量不是很大,则可以将文件读入数组变量,然后遍历数组变量的内容。
例如:
EOF
my @filecontent = <IN>;
foreach $item_of_b (@b){
foreach my $line_of_file (@filecontent){
if($line_of_file =~ /$item_of_b/){
print $line_of_file;
}
}
}
和$a
不应用作变量名,由于排序,它们是特殊的。