初めてのPerl
0による除算エラーや不正な正規表現は,プログラムをクラッシュさせる可能性がある.それら致命的なーエラーをキャッチするには,コードをevalでくくればよい.
[perl]
my $dino = 0;
eval {
$barney = $fred / $dino;
};
[/perl]
evalはwhileなどの制御構造ではなく式なので,evalの後ろにはセミコロンが必要になる.
eval内で実行されたコードが不正終了したのかどうかを調べるには,特殊変数$@が用いられる.evalが致命的なエラーをキャッチした場合,$@にメッセージがセットされる.$@が空なら,eval内のコードは正しく実行されたと考えてよい.
evalブロックの中に,他のevalブロックをネストすることもできる.内側のevalブロックでエラーをトラップすると,外側のevalブロックではエラーをトラップしない.エラーを伝播させるには,dieを使えばよい.
evalが致命的なエラーをトラップした場合,その戻り値はundefか空リストになる.そのため,上記の例では,$barneyの値がundefかどうかを調べれば致命的なエラーが起こったかどうかを知ることができるため,$@を見ることで致命的なエラーが起こったかどうかを調べる必要はない.
evalでトラップできないエラーは4種類ある.1)Perlそのものをクラッシュさせるエラー(メモリ不足,シグナル等),2)evalブロック内で発生した構文エラー(コンパイル時にキャッチされる),3)exit演算子(プログラムを終了させる),4)警告(ユーザーがwarnによって発生させた警告)からなる4つである.
リストから一部の要素だけ取り出したい,ということがよくある.リストの中から,奇数だけを取り出したい,Fredという名前が入ったものだけ取り出したい,等である.grep演算子でそれらは可能だ.
[perl]
my @odd_numbers = grep { $_ % 2} 1..1000;
#1から1000までの間で,奇数のもののみodd_numbersにpush
[/perl]
ブロックを引数に取り,そのブロック内の操作で値を返したものがリストに入る.
[perl]
my @matchin_lines = grep { /\bfred\b/i } <FILE>;
my @matchin_lines = grep /\bfred\b/i , <FILE>; #さらにシンプルに書ける!
[/perl]
数値リストを金額として一時的に表示する場合,mapを使ってリストを変換できる.
[perl]
my @data = {4.75, 1.5, 2, 1234, 6.9456, 12345678.9, 29.95};
my @formatted_data;
foreach (@data) {#この処理がmapを使うことで短縮できる
push @formatted_data, &big_money($_);
}
my @formatted_data = map{ &big_money($_) } @data;
[/perl]
map演算子は,引数の内容を$_にマップし,ブロックに渡す.
次に,ハッシュのショートカットを紹介する.ハッシュのキーを書く際は,クォートを省略できる.キーが英文字と数字と下線だけから成り,先頭が数字以外のものであれば,クォートを省略できる.このようなキーのことを裸のワード(bareword)という.
[perl]
my %score = (
barney => 195,
fred => 205,
dino => 30,
);
[/perl]
次は正規表現のコツについてだ.通常の量指定子(+や*等)は,欲張りなマッチを行う.すなわち,パターン/fred.+barney/と文字列”fred and barney went bowling last night”が合ったときに,パターンはfredとマッチしたあと,.をマッチさせる為にnightのtからじょじょにバックトラックする形でマッチの試行を行う.barneyまでマッチ試行がバックトラックしたときに初めて結果を返す.
しかしこのような欲張り型のマッチだと,あるHTML文書からタグだけ抜き出すような場合や,文章が長い場合には適さない.そこで,欲張りでないマッチを行いたい場合には,量指定子に?を付けよう.
[perl]
$str = "<html>hogehoge<bold>fuga</bold>. hogefuga<bold>hoge</bold>.</html>";
if($str =~ /<bold>(.*)<\/bold>/) {#欲張りな量指定子の時
print $1; #fuga</bold>.hogefuga<bold>hogeが出力される.
}
if($str =~ /<bold>(.*?)<\/bold>/) {#欲張りでない量指定子の時
print $1; #fugaが出力される.
}
[/perl]
また,複数行のテキストに対するマッチを行うこともできる.そのためには/mオプションを指定すれば良い.
[perl]
$_ = "I’m much better\nthan Barney is\n at bowling, \nWilma.\n";#4行のテキスト
print "found ‘wilma’ at start of line\n" if /^wilma\b/im;
[/perl]
リストはリストスライスという機能によって,その要素のいくつかだけを簡単に取り出すことができる.
例えば,以下のように.
[perl]
$_ = "1:tomoaki sano:24";
my $sano_old = (split /:/)[2];
my @names = qw/ zero one two three four five six seven eight nine /;
my @numbers = @names[9, 0, 2, 1, 0];#配列もスライスできる
my %scores = {fred => 68, dino => 110};
my @two_scores = @scores {qw/ fred dino /};#ハッシュもスライスできる
[/perl]