我想知道如何在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
Run Code Online (Sandbox Code Playgroud)
我不知道如何在一个while
循环中从两个文件一次读取一行.
TLP*_*TLP 11
好像你自己写的答案差不多.只需检查eof
两个文件句柄,如下所示:
while (not eof $fh1 and not eof $fh2) {
my $var1 = <$fh1>;
my $var2 = <$fh2>;
# do stuff
}
Run Code Online (Sandbox Code Playgroud)
更多阅读:
Sin*_*nür 10
注意:我在回答@zostay和@ jm666的评论时扩展了我的答案.
提出一个有效,清晰,简洁的问题答案的第一步,从相关变量汇总的观点开始.因此,数组@fh
将包含我们同时读取的文件句柄.
然后,我们可以从每个文件句柄中读取一行,并使用<>
运算符和map将它们存储在一个数组中.map
采用转换规则和列表,并返回另一个列表.因此:
my @lines = map scalar <$_>, @fh;
Run Code Online (Sandbox Code Playgroud)
获取文件句柄@fh
,并从每个文件句柄中读取一行(注释标量),并将这些行放入@lines
.这是一个one-to-one
转变@fh
.
作为<>
指示的文档,<>
如果到达文件结尾,则返回未定义的值,或者存在错误.
现在,检查我们是否成功读取所有文件的一种方法是检查数字定义的行是否与文件句柄的数量相同.grep选择满足特定条件的列表元素.于是
@fh == grep defined, my @lines = map <$_>, @fh;
Run Code Online (Sandbox Code Playgroud)
将检查文件句柄@fh
的数量是否与中定义的元素的数量相同@lines
.但是,@fh
这种比较的两侧出现确实令人困惑,因此检查没有未定义元素的另一种方法@lines
是:
0 == grep !defined, my @lines = map <$_>, @fh;
Run Code Online (Sandbox Code Playgroud)
如果你想把这个条件放在while循环中,你必须写:
while (0 == grep !defined, my @lines = map <$_>, @fh) {
Run Code Online (Sandbox Code Playgroud)
而如果你去一个直到,你可以简单地写:
until (grep !defined, my @lines = map <$_>, @fh) {
Run Code Online (Sandbox Code Playgroud)
这意味着" 直到至少有一个读取行返回一个未定义的值,执行循环体 ".
现在,请注意Perleof
与Ceof
不同.Perl的eof
文档说明:
实用提示:您几乎不需要
eof
在Perl中使用,因为输入操作符通常undef
在数据耗尽或遇到错误时返回.
如果你eof
每次都通过循环检查,那么你的文件IO就会翻倍,因为" 这个函数实际上是在读取一个字符,然后ungetc
是它."
我几乎总是用我的代码给出一个自包含的runnable示例.下面,我不想依赖系统中存在的任何特定文件,因此我使用始终可用DATA
和STDIN
处理.与使用该eof
函数相反,当您使用此方法时,您不必担心从哪里读取:您关心的是任何一个文件的readline是否返回了未定义的值.它也可以与任意数量的文件句柄一起使用.此外,你真的没有把文件句柄放在一个数组中,但正如我所说,相关的变量属于一个聚合,所以如果你发现自己输入像
my $var1 = <$fh1>;
my $var2 = <$fh2>;
Run Code Online (Sandbox Code Playgroud)
意识到你应该使用数组来存储文件句柄.
#!/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
Run Code Online (Sandbox Code Playgroud)
此示例脚本将停止询问您输入STDIN
何时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
Run Code Online (Sandbox Code Playgroud)
上面的循环设计为在任何一个文件耗尽时停止.另一方面,您可能希望循环运行,直到所有文件都用完为止.在这种情况下,您将使用:
while (grep defined, my @lines = map scalar <$_>, @fh) {
Run Code Online (Sandbox Code Playgroud)