「初めてのPerl」 15章 (文字列処理とソート)
1月25日にOSAKA MUSEで行われるAPOGEEのワンマンライヴの日は会社を休んでやろう!と思ってスケジュールを確認したら、Oracleの研修を受ける予定になってました…。この間、両親が大阪、京都を訪問する時期と重なってしまったのでOracleの研修は延期した(というより申し込まなかった)んだよなぁ…。研修後に行っても普通に観れるかしら。などとすっかりAPOGEEモードのbonlifeです。とりあえず、11月27日は定時退社して2nd LINEへ!
そんなこんなでPerlのお勉強です。「初めてのPerl」の15章は「文字列処理とソート」。15章の内容はだいたい以下のような感じです。
- index (部分文字列の位置を返す)
- substr (部分文字列をいじる)
- sprintf (フォーマットした文字列を変数にしまったり)
- 高度なソート (ハッシュを値でソートしたり、複数のキーでソートしたり)
このあたりは比較的とっつきやすい内容ですね。ハッシュのソートは慣れないとちょっと難しい気がしますが、なんとかなりそうです。ということで練習問題のbonlife的(not 模範)解答例です。
ex15-1.pl
- 数値のリストを読み込んで、それを数値としてソートした上で、右寄せで表示するプログラムを書く
- numbersというファイルを使う (内容は以下の通り)
17 1000 04 1.50 3.14159 -10 1.5 4 2001 90210 666 9 0 2 1 0 2001 42 -40 98.6 2.71828
#! perl use strict; use warnings; my @num_list; while (<>) { chomp; push @num_list, split(/\s/,$_); } foreach (sort { $a <=> $b } @num_list) { printf "%20s\n", $_; }
出力結果は以下の通り。
ex15-1.pl numbers -40 -10 0 0 1 1.50 1.5 2 2.71828 3.14159 04 4 9 17 42 98.6 666 1000 2001 2001 90210
解答例を見て気づいたことは以下の通り。
- splitはデフォルトでスペースで区切ってくれるので、 $_ を処理するのであれば split だけで十分
- printfのフォーマット指定で s ではなく、 g でも良い (その場合、前ゼロや小数部の末尾ののゼロが消える)
考え方は合ってましたが、細かい部分の書き方がまだまだダサいですね。こざっぱりしたコードを書けるようになりたいです。続いて2問目。
ex15-2.pl
- ハッシュのデータを、姓のアルファベット順(大文字と小文字は区別しない)でソートして表示するプログラムを書く
- 姓が同じ場合には、名(大文字と小文字は区別しない)でソート
#! perl use strict; use warnings; my %last_name = qw{ fred flintstone Wilma Flintstone Barney Rubble betty rubble Bamm-Bamm Rubble PEBBLES FLINTSTONE }; my @keys = sort { "\L$last_name{$a}" cmp "\L$last_name{$b}" or "\L$a" cmp "\L$b" } keys %last_name; foreach my $key (@keys) { printf "%-10s %-10s\n",$key ,$last_name{$key}; }
出力結果は以下の通り。
ex15-2.pl fred flintstone PEBBLES FLINTSTONE Wilma Flintstone Bamm-Bamm Rubble Barney Rubble betty rubble
解答例を見て気づいたことは特になし。ほぼ同じでした。続いて3問目。
ex15-3.pl
- ユーザから与えられた文字列の中から、与えられた部分文字列が現れる場所をすべて探し出して、その位置を表示するプログラムを書く
#! perl use strict; use warnings; print "Please input some string : "; chomp (my $value = <STDIN>); print "Please input some part string : "; chomp (my $part = <STDIN>); my $where = index($value, $part); my @position; while ($where != -1) { push @position, $where; $where = index($value, $part,$where + 1); } if (@position) { print "Matched position(s) : @position\n"; } else { print "Not matched.\n"; }
出力結果は以下の通り。
ex15-3.pl Please input some string : This is a test. Please input some part string : t Matched position(s) : 10 13
解答例を見て気づいたことは以下の通り。
- $whereがwhileループの外に出てしまっているのはスコープの面であまりよくなさそう
- forループに初期値だけ与えて、lastを使ってループを抜けるとスッキリ
- while(1)などを使っても良い
$whereの使い方がイマイチだなぁ、と思っていたら、なるほどな解説でしたよ。勉強になります。(最初、indexが3つ目の引数取れることを忘れていて、substrで文字列を切り取ったりするコードを書きかけていたのは秘密です。)
いよいよ「初めてのPerl」の終わりが近づいてきましたよ。あと2章!今週中には終わらせられそうです。細々と頑張りますよっ。