スライス
リストスライス
リストから複数の要素をまとめて取り出す。
my($day, $mon, $year) = (localtime)[3, 4, 5];
リストの要素、リストを生成する式は必ずカッコで囲まないといけない。
配列スライス
配列の要素をまとめて取り出す。配列の場合はカッコで囲む必要はない。
my @list = $nums[3, 6, 0, 3];
複数の要素をまとめて更新する。
my @list[3, 8] = ($new_id, $new_name);
ハッシュスライス
ハッシュの要素をまとめて取り出す。%ではなく@を使う。
my @list = @url{ qw/ yahoo google hatena / };
ハッシュに値をまとめてセットする。
my %zip; @zip{ @area } = @code; my @zip{ @area } = @numbers; # これはエラー
mapを使ってリストを変換する
my @list = (3.45, 29, 1446, 453456, -34, 0.0004); print map { sprintf("%6g\n", $_) } @list;
3.45 29 1446 453456 -34 0.0004
map演算子はリストの要素を$_に代入して、ブロック内のコードを実行し、その式の結果をリストの要素として返す。リストの要素をまとめて処理する時に役立ちそう。mapの場合も$_を変えると、元の要素も変わるし、ブロック内が1個の式なら、ブロックを省略できる。
高度なソート
ソートサブルーチンを使うことで、任意の順番で文字列を並び替えることができる。
sub by_reverse_num { if ($a > $b) { -1 } elseif ($a < $b) { 1 } else { 0 } }
これは数値として降順に並び替えるたソートサブルーチン。
ソートサブルーチンの引数は自動的に$aと$bに代入される。そして、$aが$bより先にあるべきなら-1を、$bの方が先にあるべきなら1を、順番がつけられない場合は0を返すようにする。また、ソートサブルーチンの中で、$aと$bを宣言したり、値を代入すると、ソートサブルーチンは正しく動作しない。
ソートサブルーチンを使うには、sortとリストの間にソートサブルーチンを置く。
my @reverse_nums = sort by_reverse_num @nums;
ソートサブルーチンがシンプルなものであれば、たいていの場合、インラインで書く。
@reverse_nums = sort { $b <=> $a } @nums;
<==>は左辺の方が小さければ-1を、左辺の方が大きければ1を、両辺が同じであれば0を返す。
文字列を比較する場合は、cmp演算子を使う。cmpの並び順はデフォルトのソートと同じなので、単に$aと$bを比較しても意味はない。
@sorted = sort { "\L$a" cmp "\L$b" } @strs;
これは、大文字と小文字を区別せずに並び替えるソートサブルーチン。
$aと$bの値を変更してしまうと、元の値も変わってしまうので、注意が必要。
ハッシュを値によってソートする
my @keys = sort { $hash{$b} <=> $hash{$a}} keys %hash;
こうすれば、値を利用してソートすることができる。
もちろんソートできるのは、keysやvaluesが返すリストであって、ハッシュそのものではない。
複数のキーでソートする
論理OR演算子を使うと、複数のキーでソートすることができる。
my @keys = sort { $hash{$b} <=> $hash{$a} or $a cmp $b } keys %hash;
まず値を数値として比較する。大きさが違えば<=>は1か-1を返すので、そこで比較は終了。値が同じであれば0を返すので、cmpによるキーの比較が行なわれる。
substrを使って部分文字列をいじる
substr(文字列, 開始位置, 文字数);
substr関数は文字列の中から、一部を取り出す。文字数を省略した場合は、開始位置から末尾までを取り出す。開始位置に負の数を指定した場合は、後ろから○文字目を開始位置とする。
my $part = substr("abcdefg", 2, 3); # cdeを返す my $part = substr("abcdefg", 4); # efgを返す my $part = substr("abcdefg", -6, 3); # bcdを返す
substrの第一引数が変数の場合、指定した部分だけを置き換えることができる。
my $str = "That's bad."; substr($str, 7, 3) = "good"; # $strは"That's good"になる。
$strは"That's good"になる。
4番目の引数として置き換え文字列を指定することもできる。
substr($str, index($str, "b"), 3, "good");
これは上と全く同じ。開始位置をindexで指定している。
indexを使って部分文字列を探す
index(文字列, 部分文字列, 開始位置)
index関数は文字列内で部分文字列が最初に現れる位置を返す。開始位置を指定すると、それより後ろから部分文字列を探す。
my $word = "abcdeabcde"; my $w1 = index($word, "a"); # $w1は0 my $w2 = index($word, "a", 3) # $w2は5
一番後ろにある部分文字列の位置を知りたい場合は、rindex関数を使う。開始位置を指定した場合は、それより前で最後に現れる部分文字列の位置を返す。
my $word = "abcdeabcde"; my $w1 = index($word, "a"); # $w1は5 my $w2 = index($word, "a", 3) # $w2は0
プロセスをファイルハンドルとして使う
逆クォートを使ってコマンドからの入力を読み込む場合は、子プロセスが終了するまで、Perlプロセスは待たなければならない。並立実行する子プロセスを起動するには、コマンドの前後どちらかに縦棒を付けたものを指定する。
open DATE, "date|"; # dateコマンドの結果がDATEに送られる open MAIL, "|mail"; # MAILに書き出したものがmailコマンドに送られる
後ろにパイプ(縦棒)を付けると入力用に、後ろにパイプを付けると出力用にオープンされる。これらをパイプオープンと呼ぶこともある。子プロセスが作れなかったらopen演算子は偽を返す。コマンドそのものが存在しなかったり、コマンドがエラーで終了した場合は、close演算子を使った時に、エラーが出る。
使い方は普通のファイルハンドルと同じ。
my $date = <DATE>; print MAIL "hoge hoge\n";
入力用のファイルハンドルに連結したプロセスが終了すると、ファイルの終わりを返す。出力用のファイルハンドルに連結したファイルハンドルをクローズすると、Perlはプロセスが終了ステータスを返すのを待つ。終了ステータスは$?変数にセットされ、その値はsystem関数が返すものと同じ。
パイプオープンを使うと、結果が得られるたびに処理していくということができる。時間がかかるコマンドの場合は、パイプオープンを使った方が、少しずつでも結果が表示されるので、いらいらしないで済むと思う。