「初めてのPerl」 17章 (上級テクニック)

お腹が空きました。bonlifeです。体重の増減はほとんどないのですが、筋力が明らかに落ちてます。運動しなきゃ…。ということで、「初めてのPerl」。最終章の17章は「上級テクニック」。「初めて」なのに「上級テクニック」ってところにほのかなエロスの薫り(違)。17章の内容はだいたい以下のような感じです。

  • evalによるエラートラップ ($@にエラーの内容がセットされる)
  • grepを使ってリストから要素を選び出す
  • mapを使ってリストを変換する
  • クォートなしのハッシュキー
  • より強力な正規表現
    • 欲ばりでない量指定子 (パターンの後に?)
    • 複数行のテキストに対するマッチ (m正規表現オプション)
  • スライス (配列スライスやハッシュスライス)

grepやmap、スライスは自由自在に使いこなせるようになりたいですね。すごく便利そうですし。正規表現についてはフクロウ本の方が遥かに詳しいですね。(当たり前ですが。)特にビックリするような内容もなかったので、練習問題のbonlife的(not 模範)解答例です。
ex17-1.pl

  • ファイルから文字列のリストを読み込み、ユーザがキーボードから対話的に入力したパターンに文字列をマッチさせる、という処理を繰り返す
  • 入力されたパターンがファイルに入っていた文字列何個にマッチしたか、および実際にマッチした文字列を表示
  • パターンを新たに入力するたびにファイルを読み直すというやり方はしない (すべての文字列をメモリ上の変数に保存)
  • パターンが正しくなければ、そのエラーを報告してから、ユーザに再びパターンを入力してもらうようにする
  • ユーザがパターンの代わりに空行を入力したら、プログラムが終了するようにする
#! perl
use strict;
use warnings;

if ($#ARGV +1 != 1 ){
    print "Please set one file name to the argument.\n";
    exit 1;
}

my $file = $ARGV[0];
my @contents;
if ( -f $file ) {
    open (IN, "$file");
    while (<IN>) {
       push @contents, $_;
    }
    close(IN);
} else {
    print "'$file' is not a readable file.\n";
    exit 1;
}
while (1){
    print "-" x 60, "\n" ;
    print "Please input some string : ";
    chomp(my $input = <STDIN>);
    if ( $input =~ /^\s*$/ ){
        print "-" x 60, "\n" ;
        print "Bye!\n";
        print "-" x 60, "\n" ;
        exit;
    }
    my @found;
    eval {
        foreach my $line (@contents) {
            if ( $line =~ /$input/ ){
                push @found, $line;
            }
        }
        my $found_number = $#found + 1;
        print "-" x 60, "\n" ;
        print "INF : '$found_number' found.\n";
        foreach (@found){
            print $_;
        }
    };
    if ($@) {
        print "-" x 60, "\n" ;
        print "ERR : An error occured ($@), continuing\n";
    }

}

出力結果は以下の通り。

C:\test\perl>ex17-1.pl sample_text
------------------------------------------------------------
Please input some string : test
------------------------------------------------------------
INF : '0' found.
------------------------------------------------------------
Please input some string : here
------------------------------------------------------------
INF : '5' found.
you and fred can sneak over there."
bring it with us. where do you keep it?"
"fred, where do you keep your bowling ball? is it in the garage?"
heard someone named barney on the line. but there is no one named
barney here. no barney at all. put that bowling ball down,
------------------------------------------------------------
Please input some string : \bask(ed)?
------------------------------------------------------------
INF : '5' found.
wilma saw this and said to betty, "you should ask barney to take
"what are we going to do for tonight?" betty asked. "wilma wants
bathroom. "what color is it?" she asked.
wilma answered the phone. "hello?" she asked.
"barney, is that you?" she asked the phone.
------------------------------------------------------------
Please input some string : (i|you
------------------------------------------------------------
ERR : An error occured (Unmatched ( in regex; marked by <-- HERE in m/( <-- HERE
 i|you/ at C:\test\perl\ex17-1.pl line 35, <STDIN> line 5.
), continuing
------------------------------------------------------------
Please input some string : want
------------------------------------------------------------
INF : '4' found.
"do you want to bring pebbles and bamm-bamm along?"
out bowling every night this week. betty and i want to go to the
romantic vacation on the rock of gibraltar. i want to win that
"what are we going to do for tonight?" betty asked. "wilma wants
------------------------------------------------------------
Please input some string :
------------------------------------------------------------
Bye!
------------------------------------------------------------

解答例を見て気づいたことは以下の通り。

  • 変数(というより配列)への値の格納はファイルハンドルの代入だけで簡単行える
  • 行の末尾の改行はchompで取り除いておいた方が良い
  • パターンにマッチする行を取り出す際、foreachで1行ずつチェックするのではなく、grepを使う

while (1)を使うあたりは良い感じでしたが、この章の上級テクニックの1つであるgrepを使わなかったので失格ですね…。なんか変だなぁ、とは思ってたんですが、またもや無理やり書いてしまいました。もうちょっと簡単に書けそうだな、と思うところはだいたいスマートな書き方がありますね。最初のうちは時間かかってもスマートかつ分かりやすい書き方を心がけていこうと思います。
ということで、ようやく「初めてのPerl」、読了です!練習問題も全て解きました。ふぅ。引き続き「続・初めてのPerl」もコツコツやっていこうと思いますので、細々と応援よろしくお願いします。