好奇心旺盛な出不精。 RSSフィード

2009-03-02

勉強する〜第6章:入出力の基本〜

振り返るシリーズ形式でやっていった方が頭にのこーる。

第6章

標準入力からの入力
chomp($line = <STDIN>); # 行を読み込んで、行末の改行文字を取り除く

ファイルの終わりに達すると、undefを返すんで、次のようにしてループから抜け出しましょう。

while (defined($line = <STDIN>)) {
  print "I saw $line";
}

これにはショートカットがあって、なんと

while (<STDIN>) {
  print "I saw $_";
}

だけでいい。なんか省略し過ぎのよーな...


ダイヤモンド演算子からの入力

ダイヤモンド演算子<>と起動引数のお話。

ダイヤモンド演算子は起動引数を標準のUnixユーティリティと同じように扱うプログラムを書くのに役立つ。catとかsedとかawkとか。

起動引数とは、cmd上でプログラムの名前の後ろに置かれる数個のwordsのこと。例えば以下のようなもの。

$ ./my_program fred barney betty # カレントディレクトリにあるコマンドmy_programを実行して、3つのファイルfred、barney、bettyを順番に処理せよ、という意味。

例えば

while (defined($line = <>)) {
  chomp($line);
  print "It was $line that I saw!\n";
}

というプログラムに起動引数fred、barney、bettyを渡して、起動すると、

"It was [ファイルfredの最初の1行] that I saw!"

"It was [ファイルfredの次の1行] that I saw!"

"It was [ファイルfredの次の1行] that I saw!"

"It was [ファイルbettyの最後の1行] that I saw!"

となる。


起動引数

ダイヤモンド演算子は、cmd上の起動引数を見ているのではなく、@ARGVという配列を見ている。

そこにcmd上の起動引数が代入される。

だから、

@ARGV = qw/ larry moe curly /; # larry、moe、curlyの3つのファイルを読ませる
while (<>) {
  chomp;
  print "It was $_ that I saw in some stooge-like file!\n";
}

と、プログラム上で@ARGVにファイルを指定してしまえば、cmd上で何を指定しようと関係なくなる。

(詳しい話は第11章で、らしい^^;)


標準出力への出力

いわずもがな、print演算子

だけんども、ちょっと出力の仕方に注意。

例えば、

@array = qw/ fred barney betty /;

があったとして、以下のような出力の違いで、結果の違いが出てくる。

print @array;
↓
fredbarneybetty
print "@array";
↓
fred barney betty

また、chompしてない行のリストだと、2行目以降がインデントされるので、

print "@array\n";

が一番無難な書き方になる(みたい)。

さらに注意することとして、"関数呼び出しのように見えるなら、それは関数呼び出しである"というPerlのルール。

$result = print("hello world!\n"); # $resultには1(真)が入力される
print (2+3)*4; # 5と表示される

ちゃんと-wしてればアラートしてくれるので、-wしときましょう!


printfによるフォーマット付き出力

printf演算子は、フォーマット文字列と表示すべき値のリストを受け取る。

フォーマット文字列は、空欄に値を埋めるテンプレートで、どんな形の出力を得たいかを示す。

以下に例を。

%g:必要に応じて自動的に浮動少数点数、整数、指数形式のどれかを選んでくれる。

printf "%g %g %g\n", 5/2, 51/17, 51 ** 17; # 2.5 3 1.0683e+29

%d:10進整数を意味する(必要ならば小数点以下を切り捨てる(四捨切捨))

printf "in %d days!\n", 17.85; # in 17 days!

数字はスペースを作る。

printf "%6d\n", 42; # ////42(/はスペース)
printf "%2d\n", 2e3 + 1.95; # 2001

%s:指定された文字列を、指定されたフィールド幅に埋め込む。

printf "%10s\n", "wilma"; # /////wilma

負の値でフィールド幅を指定すると、左寄せ。

printf "%-15s\n", "flintstone"; # flintstone/////

%f:必要に応じて出力を四捨五入する。

printf "%12f\n", 6 * 7 + 2/3;    # ///42.666667
printf "%12.3f\n", 6 * 7 + 2/3;  # //////42.667
printf "%12.0f\n", 6 * 7 + 2/3;  # //////////43

%を表わすには%%でいい。


第6章の練習問題

6-1.catのような振る舞いをするプログラムを書け。ただし、出力は逆順に行え。

※catの機能:catinate(ファイルを連結する)の略。本来は二つのファイルを連結するために使用されるコマンドだが、指定したファイルそれぞれの内容を標準出力へ書き出す

ためのコマンドとしてよく用いられる。FILEが一つも与えられないと標準入力から読み込む。

print reverse <>;

6-2.リストを1行に1個読み込んで、20文字幅の右寄せで表示させろ。
chomp (my @lines = <STDIN>);

print "1234567890" x 7, "12345\n";
foreach (@lines) {
  printf "%20s\n", $_;
}

6-3.6-2の文字幅をキーボードから指定できるようにしろ。
chomp (my $width = <STDIN>);
chomp (my @lines = <STDIN>);

print "1234567890" x (($width+9)/10), "\n"; # 四捨切捨になることに注意!
foreach (@lines) {
  printf "%${width}s\n", $_;
}

総括

ああ、スピードが上がらない・・・