| Top Page | プログラミング | Perl 目次 | prev | next | 索引 |
大きなトピックではないのでこれまでの解説には出てこなかったけど, 知ってると便利なことをいくつか集めました.
プログラムの実行中に,人間かキーボードからデータを入力して,対話的に 処理を進めたいことがあります.その場合,STDIN という特別なファイルハンドル を使います.このハンドル(すわなち窓口)は,ふつうのファイルではなくて, 標準入力とよばれるものの入力窓口になっています.キーボードからの入力は, この標準入力から読み込むことができます.
…などという説明ではよく分からないので,例を見ましょう.
$max_n = 10;
$lucky_number = int (rand() * ($max_n +1)); # $lucky_number は 0〜$max_nの整数
print "今日のラッキーナンバーを当ててごらん (0 〜 $max_n).";
while ($guess = <STDIN>) { # キーボードからの入力.
chomp $guess; # 行末の改行コードを除く
if ($guess == $lucky_number) { # 当たりか?
print "当たり!\n";
exit();
}
else {
print "まあ,運がなかったということでしょう.\n";
print "めげずにもう一回いってみよう.";
}
}
print "もうあきらめたか.根性ないねえ.\n";
いくらやっても当たらずに途中でやめたくなったら,
ファイルテスト演算子というものを使うと,ファイルの性質を簡単に知る ことができます.全部で 20 個以上の演算子がありますが,よく使うのは, 指定した名前のファイルが存在するかどうかを調べる -e です. -e のあとにファイル名を書きます.ファイルが存在したら真,存在しなかったら 偽が返ります.
たとえば,こんなふうに使えます.
$new_file = shift @ARGV; # 作製するファイル名をコマンドライン引数から取得
if (-e $new_file) { # その名前のファイルがすでにあったら…
print "file $new_file already exists. Continue this job? y/n"; # 続けるか確認を要求
$answer = <STDIN>; # キーボードからの入力(説明したばかりです).
chomp $answer; # 行末の改行コードを削除.
if ($answer =~ m/n/i) { # 大文字小文字と区別せず,n とマッチするかチェック
exit; # マッチしたらそこで終了
}
}
# 以下,処理を続ける.
キーボード(標準入力)からの入力や,パターンマッチなどもでてきて復習に なりますね.m// は i オプションをつけて,大文字の N でも小文字の n でも NO の意味に解釈するようにしてあります.
-e のほか,ディレクトリかどうかを調べるファイルテスト演算子 -d は, あるディレクトリのなかのサブディレクトリをたどりたいときに役にたちます.
プログラム中にじかに書いた文字列データ(文字列リテラル)をいくつも配列に しまいたいとき,いちいち引用符でくくるのはけっこう面倒です. 引用符なしで文字列リテラルのリストを書きたいときには,qw( ) で括るという 方法があります.
@languages = qw(Perl awk C C++ Ruby Python Java FORTRAN COBOL BASIC Lisp);
foreach $language (@languages) {
print $language, "\n";
}
qw( ) 内では,文字列の間をコンマで区切りません.空白が区切りになります. ちょうど空白を区切りにして split したのと同じリストが生成されます. だから,文字列に空白がある場合には使えません.
文字列リテラルを並べたリストからハッシュを作ることができます. リストには,キーと値のペアをいくつも並べて書いていきます.
%mountain_heights = ('Fujisan', 3776,
'Kitadake', 3192,
'Yarigatake', 3180,
'Tsukubasan', 876);
foreach $mountain (keys %mountain_heights) {
print $mountain, "\t", $mountain_heights{$mountain}, "\n";
}
この変形として, キーと値の間のコンマのかわりに => と書くことができます.
%mountain_heights = (Fujisan => 3776,
Kitadake => 3192,
Yarigatake => 3180,
Tsukubasan => 876);
foreach $mountain (keys %mountain_heights) {
print $mountain, "\t", $mountain_heights{$mountain}, "\n";
}
=> を使う場合,キーとなる文字列は引用符号で囲む必要がありません (囲ってもいいけど). この表記法だと,キーと値の組み合わせがはっきり見えるという利点があります.
※(追記) Windows 上の ActivePerl (5.6.0ベース)では,キーになる文字列が 日本語の場合には引用符で囲まないとだめみたいです.他の環境ではどうなるか 分かりません.
ところで,サブルーチンには引数としていくつものスカラー変数やリテラルを 渡すことができました.それらは,サブルーチンのなかでは @_ という名前の 配列にしまわれており,必要に応じて各要素の値を使いました (>サブルーチンのページ).
サブルーチンの引数のところにハッシュ変数を書くと(ハッシュはリストコンテキスト で評価され),キーと値のペアがずらずらと並んだリストになって @_ にしまわれます. ちょうど,上のリストからハッシュを作るのと逆ですね.ためしにこんなプログラムを 動かしてみます.
%mountain_heights = (Fujisan => 3776,
Kitadake => 3192,
Yarigatake => 3180,
Tsukubasan => 876);
&show_items(%mountain_heights);
sub show_items
{
foreach $item (@_) {
print $item, "\n";
}
}
すると,こんな出力が得られて,キー,値,キー,値,…というデータの並びが @_ にしまわれていることが分かります.
Kitadake 3192 Fujisan 3776 Tsukubasan 876 Yarigatake 3180
さて,それならば,サブルーチンのなかでもう一度ハッシュに戻すことも簡単に できますね.
%mountain_heights = (Fujisan => 3776,
Kitadake => 3192,
Yarigatake => 3180,
Tsukubasan => 876);
&show_items(%mountain_heights);
sub show_items
{
my %local_hash = @_; # キー,値,キー,値…という配列からハッシュを作る
foreach $mountain (keys %local_hash) {
print $mountain, "\t", $local_hash{$mountain}, "\n";
}
}
この手を使ってサブルーチンにハッシュを渡すことができますが, 複数のハッシュを渡したかったり,他の変数も渡したかったりする場合には, @_ 中のデータのどこからどこまでがひとつのハッシュのキーと値を並べたもの なのかが分からず,簡単には行きません. そこで便利なのが例のリファレンスというものです.いよいよ次のページで登場します.
そんな場合,実行させたくない部分の各行の先頭に # をつけて, コメントにしてしまえばよいのです.プログラム中の文をコメントにしてしまうことを コメントアウトと言います(ということは だいぶ前にも一度でてきました). でも,飛ばしたい行が数行ぐらいならともかく,10行も20行もあたまに # を つけたり,また実行させたくなっていちいち # を取ったりするのは面倒です.
そんなときに使える方法を紹介します. 行の最初の文字に =,それに続けて適当な文字列を書いておくと,そこから先は コメントとして無視されます.そのあと,行頭から =cut と書いてある行があると,その次からプログラムとしての解釈を再開します.
例です.@data という配列にしまったデータを使ってなにかをするプログラム を書いたとします.本番ではファイルからデータを読み込んで処理しますが, まずはテスト用に少数のデータを @data に入れて走らせてみたいとします. その場合,こんなふうに書いておくと便利です.
@data = (1, 2); # テスト用のデータ
=comment # ここからコメント
@data = ();
while ($line = <>) { # ファイルからデータを読み込む
chomp $line;
($x, $y) = split /\s+/, $line;
push @data, ($x + $y);
}
=cut # ここまでコメント
foreach $data (@data) {
print $data, "\n";
# $data を使っていろいろな処理.
}
上のプログラムでは,ファイルからのデータ読み込みの部分がそっくり
コメントアウトされています.
さらに,コメントの開始と終了の行を # を使ってコメントアウトしてしまえば, データ読み込み部分が生きます.こんなふうに.
@data = (1, 2); # テスト用のデータ
# =comment # コメント開始のマークをコメントアウト
@data = ();
while ($line = <>) { # ファイルからデータを読み込む
chomp $line;
($x, $y) = split /\s+/, $line;
push @data, ($x + $y);
}
# =cut # コメント終了のマークをコメントアウト
foreach $data (@data) {
print $data, "\n";
# $data を使っていろいろな処理.
}