我想知道如何在Perl中实现它:
while ( not the end of the files )
$var1 = read a line from file 1
$var2 = read a line from file 2
# operate on variables
end while
我不确定如何在一个while
循环中从两个文件一次读取一行。
答案 0 :(得分:11)
好像你自己写的答案差不多了。只需检查两个文件句柄的eof
,如下所示:
while (not eof $fh1 and not eof $fh2) {
my $var1 = <$fh1>;
my $var2 = <$fh2>;
# do stuff
}
更多阅读:
答案 1 :(得分:10)
注意:我扩展了我的回答以回应@zostay和@ jm666的评论。
为这个问题提出一个有效,清晰,简洁的答案的第一步,从相关variables go in an aggregate的想法开始。因此,数组@fh
将包含我们同时读取的文件句柄。
然后,我们可以从每个文件句柄中读取一行,并使用<>
运算符和map将它们存储在一个数组中。 map
采用转换规则和列表,并返回另一个列表。因此:
my @lines = map scalar <$_>, @fh;
获取@fh
中的文件句柄,并从每个文件句柄中读取一行(注意scalar),并将这些行放在@lines
中。这是one-to-one
的{{1}}转换。
正如@fh
的文档所示,如果到达文件末尾,<>
将返回未定义的值,或者出现错误。
现在,检查我们是否成功读取所有文件的一种方法是检查数字defined行是否与文件句柄的数量相同。 grep选择满足特定条件的列表元素。因此
<>
将检查@fh == grep defined, my @lines = map <$_>, @fh;
中的文件句柄数是否与@fh
中定义的元素数相同。但是,此比较两侧出现的@lines
确实令人困惑,因此检查@fh
中没有未定义元素的另一种方法是:
@lines
如果你想把这个条件放在while循环中,你必须写:
0 == grep !defined, my @lines = map <$_>, @fh;
如果你选择until,你可以简单地写一下:
while (0 == grep !defined, my @lines = map <$_>, @fh) {
这意味着“直到至少有一条读取线返回未定义的值,执行循环体”。
现在,请注意Perl's eof
与C's eof
不同。 Perl's eof
的文档指出:
实用提示:您几乎不需要在Perl中使用
until (grep !defined, my @lines = map <$_>, @fh) {
,因为输入操作符通常会在数据耗尽或遇到错误时返回eof
。
如果每次循环都检查undef
,那么你的文件IO就会翻倍,因为“这个函数实际上是在读取一个字符,然后是eof
它的。”
我几乎总是用我的代码给出一个自包含的runnable示例。下面,我不想依赖系统上现有的任何特定文件,因此我使用始终可用的ungetc
和DATA
句柄。与使用STDIN
函数相反,当您使用此方法时,您不必担心从哪里读取:您关心的是任何一个文件的readline是否返回undefined值。它也可以与任意数量的文件句柄一起使用。另外,你真的没有把文件句柄放在一个数组中,但正如我所说,相关的变量属于一个聚合,所以如果你发现自己输入类似
eof
意识到you should have used an array to store the filehandles。
my $var1 = <$fh1>;
my $var2 = <$fh2>;
当#!/usr/bin/env perl
use strict; use warnings;
my @fh = (\*DATA, \*STDIN);
until (grep !defined, my @lines = map scalar <$_>, @fh) {
print for @lines;
}
__DATA__
one
two
three
中的行用尽时,此示例脚本将停止询问您在STDIN
上的输入。如果脚本中没有任何尾随空白行,则必须在脚本终止之前输入 three 四行。
现在,如果您想知道哪些文件句柄到达目的地,您将切换到使用类似的内容:
DATA
上面的循环用于在任何一个文件耗尽时停止。另一方面,您可能希望循环运行,直到所有文件都用完为止。在这种情况下,您可以使用:
#!/usr/bin/env perl
use strict; use warnings;
my @fh = (\*DATA, \*STDIN);
while (1) {
my @lines = map scalar <$_>, @fh;
if (my @eof = grep !defined($lines[$_]), 0 .. $#fh) {
warn "Could not read from filehandle(s) '@eof'";
last;
}
print for @lines;
}
__DATA__
one
two
three
答案 2 :(得分:2)
没有明确eof()
检查的另一个简单解决方案是这样的:
while (defined(my $var1 = <$fh1>) and defined(my $var2 = <$fh2>)) {
# do stuff
}
这使用<>
返回undef
的事实,如果&amp;只有当你在档案的最后。