| Top Page | プログラミング | Perl 目次 | prev | next | 索引 |

21. こまごまとした(有用な)補足

大きなトピックではないのでこれまでの解説には出てこなかったけど, 知ってると便利なことをいくつか集めました.


キーボードからのデータ入力

プログラムの実行中に,人間かキーボードからデータを入力して,対話的に 処理を進めたいことがあります.その場合,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";

いくらやっても当たらずに途中でやめたくなったら,

という2つの方法で終わることができます. ぜひ動作を試してみてください.


ファイルテスト演算子

ファイルテスト演算子というものを使うと,ファイルの性質を簡単に知る ことができます.全部で 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 を使っていろいろな処理.
}


| Top Page | プログラミング | Perl 目次 | prev | next |