「初めてのPerl」 16章 (単純なデータベース)
2007年の手帳はほぼ日手帳2007で良いかなぁ、と思っているbonlifeです。流行に踊らされたいです。「1日教養、1日休養」ということでお勉強、お勉強です。「初めてのPerl」の16章は「単純なデータベース」。RDBMSとかじゃなく、DBMですね。16章の内容はだいたい以下のような感じです。
- DBMハッシュのオープン、クローズ (dbmopen, dbmclose)
- DBMハッシュを使う (スキャンする時はeach関数使った方が良い)
- packとunpackを使ってデータを加工
- 固定長ランダムアクセスデータベース (seek, read)
- 可変長(テキスト)データベース
- コマンドラインから書き戻し編集 (-e, -p)
要するにハッシュをファイルに保存するってことですかね。なんか違うのかな。操作自体は特に難しくなさそうです。ということで早速練習問題のbonlife的(not 模範)解答例です。
ex16-1.pl
- perlfunc.podファイルを読んで、その中から=item行に置かれている識別子名を探し出すプログラムを書く
- 各識別子が登場する最初の行番号を記録したデータベースを作成する
- 特殊変数$.には最後に入力した行の行番号が入っている
#! perl use strict; use warnings; @ARGV = `perldoc -l perlfunc`; dbmopen(my %DATA, "perlfunc_database", 0644) or die "Cannot create perlfunc_database : $!"; while (<>) { if ( /=item (.*?)\s/ ) { if (! defined $DATA{"$1"}) { $DATA{"$1"} = $. ; } } } #foreach my $key (keys %DATA) { # print "$key appears in the $DATA{$key} line.\n"; #} dbmclose(%DATA);
出力結果はなし。解答例を見て気づいたことは以下の通り。
- ファイルは@ARGV使って無理やりダイヤモンド演算子で読み込むよりも、ちゃんとファイルハンドラを使った方が良いような
- 正規表現が雑過ぎる (^は必要)
- %DATAの初期化(空にすること)を行っていない
- definedを使う判定ではなく、||を使って前から順に評価することで「最初の行番号」の取得が可能
- 処理完了後のメッセージがあった方が良い
簡単そう!と思って適当に書いた感丸出しです(恥)。4点目の || を使って前の処理が false の時のみ後ろの処理を実行する、みたいなのはかなりPerlっぽいですよね。このあたりを使いこなせるようになりたいです。そんなこんなで、2問目。
ex16-2.pl
#! perl use strict; use warnings; if ($#ARGV +1 != 1 ){ print "Please set one function name to the argument.\n"; exit 1; } dbmopen(my %DATA, "perlfunc_database", 0644) or die "Cannot open perlfunc_database : $!"; if ( defined $DATA{$ARGV[0]} ) { print "'$ARGV[0]' appears $DATA{$ARGV[0]} line firstly.\n"; } else { print "Function '$ARGV[0]' doesn't exist.\n"; } dbmclose(%DATA);
出力結果は以下の通り。
ex16-2.pl shift 'shift' appears 4812 line firstly.
ex16-2.pl shifto Function 'shifto' doesn't exist.
解答例を見て気づいたことは以下の通り。
- このプログラムはデータベースが存在しなければ動作しないので、dbmopenの第3パラメータにはundefを指定した方が良い
- || を使ってハッシュに値がある場合とない場合のメッセージを分けると格好良い
なるほど、といったところですね。(やっぱり || は使いこなしたい!)続いて、3問目。
ex16-3.pl
- 問題2のプログラムを改造して、データベースから関数を見つけたら、ページャプログラムを起動して、perlfunc.podファイルのその行を見られるようにする
- less +1234 filename のように起動するとそのファイルの1234行目を見ることができる
#! perl use strict; use warnings; if ($#ARGV +1 != 1 ){ print "Please set one function name to the argument.\n"; exit 1; } my $file = `perldoc -l perlfunc`; dbmopen(my %DATA, "perlfunc_database", 0644) or die "Cannot open perlfunc_database : $!"; if ( defined $DATA{$ARGV[0]} ) { my $start_line = $DATA{$ARGV[0]} - 1 ; # exec 'more', "+${start_line}", $file; system "more +${start_line} $file"; } else { print "Function '$ARGV[0]' doesn't exist.\n"; } dbmclose(%DATA);
出力結果は以下の通り。
ex16-3.pl shift =item shift ARRAY X<shift> =item shift (中略) ^CTerminating on signal SIGINT(2)
なぜかexecを使うとmoreの動きがおかしかったので、systemを使いました。その結果、Ctrl+Cで終了したので、SIGINT(2)で終わってます。解答例を見て気づいたことは以下の通り。
- ページャを起動する部分にも or die を書いた方が良い
- execを使っている
- ページャに渡す行番号はデータベースで見つかった行番号 (DOSコマンドのmoreの場合、データベースに格納した行番号をそのまま渡すと =item の次の行から表示されてしまったので、-1 してしまいました)
素直にUNIX(というよりLinux)環境でやった方が良い気がずーっとしてますが、まぁ、そこは気にしない方向で。時間はかかりましたが、なんとかここまでやってきました。残すは17章のみ。一気に片付けます!