知ってそうで意外と知られていないperlの小技 10選
意外と知られていないperlテクってのが、意外とあるもんですね。
最近身の回りでいくつか話題に上がったものがあったので、ちょっと書いてみます。
どれも最新のモダパ的なモノではないけども、知っておくと地味に便利かもしれないノウハウです。
中級レベル以上のperlユーザの人たちでも「お、こんなの知らなかった」というのもあるかもね。
複数項目でのソート
よくエクセルなんかで「A列を降順、B列を昇順にして並び替え」みたいなことしますよね?
perlで複数項目のsortではどうすればできるでしょうか?
じつはとっても簡単。sortの次に続くブロックの中でorするだけです。
例えば以下のような4人の子供たちのデータを年齢順、体重順でソートしてみます。
use strict; my @data = ( { name => '太郎', age => 10, weight => 25, }, { name => '花子', age => 9, weight => 23, }, { name => '次郎', age => 10, weight => 27, }, { name => 'よし子', age => 9, weight => 21, }, ); my @sorted = sort { $b->{age} <=> $a->{age} || $b->{weight} <=> $a->{weight} } @data; for (@sorted) { print $_->{name}, "\t", $_->{age}, "歳\t", $_->{weight}, "キロ\n"; }
次郎 10歳 27キロ
太郎 10歳 25キロ
花子 9歳 23キロ
よし子 9歳 21キロ
おお、簡単ですね。
これを知らないとうっかり自分で関数を書いてしまいそうになります。ひゃー。
ランダムシャッフル
続いてこれもソートねた。
配列をランダムにシャッフルします。
use Data::Dumper; my @data = qw( 0 1 2 3 4 5 6 7 8 9 ); my @shuffle = sort { rand() <=> 0.5 } @data; print Dumper \@shuffle; #結果はランダムにシャッフルされている
え、これだけ?なんで?って思うかもしれませんが、よーく考えてみてください。
ふーむ。よく考えたもんだ!
GUIアプリをつくる
がらっと志向を変えてみます。
実はperlでwindowsアプリを作れるって知ってましたか?
Win32::GUIとWin32::GUI::Loftを使えば簡単にGUIアプリケーションを作れてしまいます。
もしくはGtkとGtk2::GladeXMLを使えばwindowsだけでなくmacやlinuxな環境でも動作するGUIアプリを作れれます。
これらのツールで書いたスクリプトをPARで実行可能なバイナリ形式にパックすれば、perlインタプリタが入っていない環境にも配布できるよ!
具体的に書いているとすごい量になってしまうので参考サイトを書いておきます。
http://blog.remora.cx/2010/03/gui-programming-with-win32-gui-loft.html
http://perl-mongers.org/2008/06/perl-and-gtk.html
あとついでにWin32::GuiTestを紹介しておきます。
これのSendKeysという関数をうまく使えば、フォームなどへのデータの流し込みとかができて面白いです。
周りの人に見せると、たぶんびっくりされます。
http://perldoc.jp/docs/modules/Win32-GuiTest-1.3/GuiTest.pod
ハッシュと配列の相互変換
perlの中級者ぐらいの人でも以外と知らない事実。
実はハッシュをアレイコンテキストで評価すると配列になります。
逆もしかりです。
my %hash = ( 'ブレンド' => 540, 'アメリカン' => 540, 'カフェオーレ' => 650 ); my @array = %hash; # @arrayの中身は qw( 'ブレンド' 540 'アメリカン' 540 'カフェオーレ' 650 ) my %hash2 = @array; #%hash2の中身はは%hashと同じ
この性質はクラスのコンストラクタでよく使われているテクだったりします。
sub new { my $class = shift; my %args = @_; return bless \%args, $class; }
デフォルト引数を設定する場合なんか、こういう風に書かれたりもします。
sub new { my $class = shift; my %args = ( foo => 'bar', hoge => 'fuga', @_ ); return bless \%args, $class; }
なるほどね。って感じではないでしょうか。
evalのあぶない使い方
evalと言えば例外処理、という固定観念はありませんか?
evalはもっとエキサイティングな用途でも使えます。
evalは渡されブロックをperlスクリプトとして実行します。
なので動的に文字列としてプログラムコードを生成して、それを実行させることができるわけです。
わざとらしい例を1つあげます。
ログを集計する場合に「店舗別の月別の商品別の販売個数を集計したい」というようなタスクがあったとします。
でもこの「○別の△別の〜」といった集計項目が何個あるか、プログラムを実行するまでわからないような条件であったとしましょう。
(現実的にはそんな条件ってないと思うけど)
use strict; use Data::Dumper; my $data; while (<DATA>) { chomp $_; # 一番最後のカラムに数値が入っているつもり # それ以外のカラムは集計軸として使うという前提 my @f = split( "\t", $_ ); my $value = pop @f; # 動的にデータ構造を作る my $string = '$data'; for (@f) { $string .= '->{\'' . $_ . '\'}'; } $string .= '+=' . $value . ';'; # エバる eval $string; } print Dumper $data; __DATA__ 横浜店 2010年05月 商品A 割引なし 2 横浜店 2010年06月 商品A 割引あり 7 田町店 2010年06月 商品A 割引なし 2 田町店 2010年05月 商品B 割引なし 4 横浜店 2010年06月 商品C 割引なし 8 横浜店 2010年06月 商品C 割引あり 12
なんと、事前に定義することなく動的に多段のハッシュなデータ構造ができてしまいました。
でも、ある意味でこれはとても危険な行為です。ログの文字列にへんなコードが混入してたらアウト。1行ごとのevalするので実行速度も遅いしね。
くわしくはこちらを見てください。
http://blog.livedoor.jp/dankogai/archives/51175261.html
しかしリスクを十分わかった上で、使いどころを間違えなければ、evalは十分に便利な道具です。私はevalが以外とすきです。
perltidy
どんなにいいコードを書いてもインデントの幅がまちまちだったり、きたなーい感じのソースだとイマイチですよね。
そんなときはPerl::Tidyでソースコードを整形してあげましょう。一発でプロっぽい見栄えに変身します。
さぁ、今すぐ cpan -i Perl::Tidy しましょう。perltidyというコマンドが使えるようになります。
use strict; use warnings; for(1.. 10){ print $_; print "\n"; }
こんな悲しくなるほどきたないコードが
use strict; use warnings; for ( 1 .. 10 ) { print $_; print "\n"; }
おお、まっとうな見栄えになりました。
vimつかってるならば :%!perltidy とするだけどOK!
とても便利です。
perlとだけ叩いたら
perlはコードを書いてファイルに保存して実行させるか、-e オプションでワンライナーとして実行させるか、どちらかで動かすものと考えていませんか?
そんなあなたは、まずコンソールに向かって「perl」とだけ打ってリターンしてみてください。
続いて print "hello world\n"; と叩いてみてください。
最後にCtrl-D。
おお!こんな動かしたもあったのか!
って知ってましたか?常識だったかな?
モジュールの格納場所をしる
@INCはとても有名。perlユーザならだれもが知ってる特殊変数ですね。
インクルードパスが格納されています。
一方、なぜか %INC は知名度が低いようです。
%INCにはそのプログラムでロードしているモジュールのパスがハッシュとして格納されています。
use LWP::Simple; while ( my ( $key, $value ) = each %INC ) { print $key, "\t", $value, "\n"; }
これをじっこするとこうなります。
Godzilla:Hacks miki$ perl test.pl
warnings.pm /System/Library/Perl/5.10.0/warnings.pm
warnings/register.pm /System/Library/Perl/5.10.0/warnings/register.pm
LWP/Simple.pm /System/Library/Perl/Extras/5.10.0/LWP/Simple.pm
Exporter/Heavy.pm /System/Library/Perl/5.10.0/Exporter/Heavy.pm
Exporter.pm /System/Library/Perl/5.10.0/Exporter.pm
HTTP/Status.pm /System/Library/Perl/Extras/5.10.0/HTTP/Status.pm
vars.pm /System/Library/Perl/5.10.0/vars.pm
strict.pm /System/Library/Perl/5.10.0/strict.pm
モジュールを書いていて、そのモジュール自身がインストールされている場所を知りたい、なんて時にはこのハッシュから自分自身のパッケージ名を探せばパスがわかります。
知っておくとちょっと便利です。
モジュールのメソッドを上書きする
CPANモジュールを使っていて、「ここのメソッドのこの処理、どうしてもちょっとだけ変えたいんだよなぁ」というようなケースってありますよね?
わざわざ継承するのも大げさっていうような場合は思い切ってそのクラスの当該メソッドを再定義してしまいましょう!
use strict; use warnings; package Foo; sub do_something { print "なにか処理します", "\n"; } package main; # オリジナルのメソッドのコードリファレンスを保持しておく my $origin = Foo->can('do_something'); # 型グロブで上書き no warnings 'redefine'; *Foo::do_something = sub { print "このメソッドはノットッタゼ!", "\n"; }; # 実行してみる Foo->do_something(); #ノットタレタゼ! # もとに戻す no warnings 'redefine'; *Foo::do_something = sub { $origin->(); }; # もう1回実行してみる Foo->do_something(); # なにか処理します
実行結果はこうなります。
このメソッドはノットッタゼ!
なにか処理します
ちょっとお行儀わるいかもしれませんが、知っておくと便利なテクですね。
perldocをもう少し
perldocって便利ですよね。わざわざブラウザでCPANサイトに行かなくてもPODのドキュメントをコンソールで閲覧できるわけです。
そんな便利なperldocをもう少しだけ便利に使うオプションです。
モジュールの格納されているパスを知るためには -l オプションをつけます。
perldoc -l
Godzilla:Hacks miki$ perldoc -l JSON
/Library/Perl/5.10.0/JSON.pm
さらにソースを直接みたい場合は -m オプションでソースを開くことができます。
perldocは便利だなぁ。
以上、なんの脈絡もなく10個の「意外と知られていないテクニック」を紹介してみました。
enjoy!