私はPerlは初めてですが、Cは少し知っています。教室のメモの 1 つで、このスニペットに出くわしました。
$STUFF = "C:/scripts/stuff.txt";
open STUFF or die "Cannot open $STUFF for read: $!";
print "Line $. is: $_" while (<STUFF>);
ステートメントのwhile
後にあるのはなぜですか? print
それは何をするためのものか?
私はPerlは初めてですが、Cは少し知っています。教室のメモの 1 つで、このスニペットに出くわしました。
$STUFF = "C:/scripts/stuff.txt";
open STUFF or die "Cannot open $STUFF for read: $!";
print "Line $. is: $_" while (<STUFF>);
ステートメントのwhile
後にあるのはなぜですか? print
それは何をするためのものか?
と同じです
while (<STUFF>) {
print "Line $. is : $_";
}
よりシンプルでコンパクトなため、このように記述されています。これは、一般に、Perl の(in)有名な条件とループの「ステートメント修飾子」形式です。
他の回答は、while
ループのステートメント修飾子形式を説明しています。ただし、ここでは他にも多くの魔法が行われています。特に、スクリプトは Perl の 3 つの特殊変数に依存しています。これらのうちの 2 つ ($_
と$!
) は非常に一般的です。もう一方 ( $.
) はかなり一般的です。しかし、それらはすべて知っておく価値があります。
開いているファイルハンドルで実行するwhile <$fh>
と、Perl は自動的にファイルを 1 行ずつ実行し、EOF
. 各ループ内で、$_
何もしなくても現在の行が に設定されます。したがって、これら 2 つは同じです。
while (<$fh>) { # something }
while (defined($_ = <$fh>)) { # something }
perldoc perlop
の I/O 演算子に関するセクションを参照してください。(これは不思議すぎるwhile (my $line = <$fh>)
と思う人もいるので、代わりに使用します。これにより、より明確な変数名である$line
ではなく、行ごとに表示され$_
ますが、より多くの入力が必要になります。それぞれに独自のものです。)
$!
システムエラーの値を保持します (設定されている場合)。これをいつどのように使用するかについてperldoc perlvar
は、 のセクションを参照してください。$OS_ERROR
$.
行番号を保持します。perldoc perlvar
のセクションを参照してください$NR
。この変数は驚くほどトリッキーです。現在読んでいるファイルの行番号が必ずしも含まれているとは限りません。例:
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
print "$ARGV: $.\n";
}
これを として保存して としてlines
実行するとperl lines file1 file2 file3
、Perl は file1、file2、file3 の順に行を数えます。Perl がどのファイルから読み取っているのかを認識していることがわかります (ファイル名は $ARGV にあります。ファイル名は正しいはずです) が、各ファイルの末尾で自動的に行番号をリセットしません。これについて言及するのは、最終的に(厚い)頭蓋骨を通り抜けるまで、この行動に何度も噛まれたからです. この方法で個々のファイルを追跡するために番号付けをリセットできます。
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
print "$ARGV: $.\n";
}
continue {
close ARGV if eof;
}
また、プラグマstrict
とwarnings
プラグマを調べて、新しい 3 引数形式の を調べてくださいopen
。あなたが "不明 (google) " であることに気付きました。これは、二度と戻ってこない可能性が高いことを意味します。少なくとも、その日はタイピングの練習をしたと思います。
プリントの後に を配置すると、while
通常の英語のように読むことができます。
また、 のprint
代わりに に重点を置いていwhile
ます。そして、中括弧は必要ありません:{ ... }
if
や と一緒に使用することもできますunless
。たとえば、
print "Debug: foobar=$foobar\n" if $DEBUG;
print "Load file...\n" unless $QUIET;
次のスニペットはまったく同じもので、同じことを異なる方法で記述しただけです。
print "Line $. is : $_" while (<STUFF>);
while (<STUFF>) {
print "Line $. is : $_";
}
これが行うことは、ループを通る各反復であり、Perl はファイルから 1 行のテキストを読み取り、STUFF
それを特殊変数に入れます$_
(これが山括弧の機能です)。次に、ループの本体に次のような行が出力されます。
1行目: test 2 行目: ファイル
特殊変数$.
は、ファイルから読み取られた最後の行の行番号であり$_
、山かっこ演算子によって設定されたその行の内容です。
私はあなたのスニペットを私がするように書き直す自由を取りました。
私が提案したコードの下には、実際に見られる可能性のある最適とは言えない方法のローグギャラリーがあります。
use strict;
use warnings;
my $stuff_path = 'c:/scripts/stuff.txt';
open (my $stuff, '<', $stuff_path)
or die "Cannot open'$stuff_path' for read : $!\n";
# My preferred method to loop over a file line by line:
# while loop with explicit variable
while( my $line = <$stuff> ) {
print "Line $. is : $line\n";
}
あなたが見るかもしれない他の方法はここにあります。上記の例では、それぞれをwhileループの代わりに使用できます。
# while statement modifier
# - OK, but less clear than explicit code above.
print "Line $. is : $_" while <$stuff>;
# while loop
# - OK, but if I am operating on $_ explicitly, I prefer to use an explicit variable.
while( <$stuff> ) {
print "Line $. is : $_";
}
# for statement modifier
# - inefficient
# - loads whole file into memory
print "Line $. is : $_" for <$stuff>;
# for loop - inefficient
# - loads whole file into memory;
for( <$stuff> ) {
print "Line $. is : $_\n";
}
# for loop with explicit variable
# - inefficient
# - loads whole file into memory;
for my $line ( <$stuff> ) {
print "Line $. is : $line\n";
}
# Exotica -
# map and print
# - inefficient
# - loads whole file into memory
# - stores complete output in memory
print map "Line $. is : $_\n", <$stuff>;
# Using readline rather than <>
# - Alright, but overly verbose
while( defined (my $line = readline($stuff) ) {
print "Line $. is : $line\n";
}
# Using IO::Handle methods on a lexical filehandle
# - Alright, but overly verbose
use IO::Handle;
while( defined (my $line = $stuff->readline) ) {
print "Line $. is : $line\n";
}
while
ステートメントは、ワンライナーの場合にのみループ本体をたどることができることに注意してください。ループ本体が複数の行にまたがる場合while
は、その前に配置する必要があります。
以下と同じです。
while (<STUFF>) { print "Line $. is: $_"; }