perlは素晴らしい

perlは素晴らしい。もはやひとつのプログラミング言語であるのを超えて、フレームワークとなっている。いろんな言語やフレームワークに触れてきたが、これほど便利で使いやすく応用範囲もひろいものは例がない。

もっと早く知っておきたかった。 実際に知ったのはもうかなり前で、インターネットというものにつなぎはじめて、「ホームページ」をつくり、そこにCGIを設置する、というときに、よくわからないままperlのソースを写していて、クォーテーションがシングルだったりバックだったりダブルだったりするのがなぜかもわからず、わかろうともせずにいた。 perl以外で感動したものは、delphi, dbMAGIC, secondlife, C#くらいだろうか。 でも、便利さと書きやすさ、読みやすさはperlが群を抜いている。その理由は、書かなくてもよいデフォルト値の存在と、書式が柔軟というか厳密でないというところ。 たとえばファイルを読むときにレコードが格納される変数$_とか、foreachとか、chompとか。

「perlのソースは読みにくい」というのを何度か聞いたことがあるし、自分でもそう思っていたが、その理由のほとんどは正規表現である。正規表現は、簡潔で有用にしようとするとわけがわからなくなる。しかし、正規表現も柔軟で、厳密さを問わなければかなりわかりやすく書くことができる。 モジュールも豊富であり、そのインストールもコマンド一発で可能であり、linuxでもwindowsでもほとんど同じように使用できる。いままでC言語でポインタがどうの文字列の抽出や検索がどうの、ということは、perlと正規表現を知った今となっては一体なんだったのかと思う。

私が後進にすすめるとしたら、とにかく必須のものとしてc。公私にわたるツールとしてperl。私的なwindows限定ツールとしてdelphi。cとperlは必須である。 あとは、javasctipt, vbscript, MSofficeのVBA(マクロ)、かな。 delphiは開発ツールの理想の姿として、知っておくべきだと思う。これは言語とライブラリとIDEを含めたもの、フレームワークとして。 あとphpもかな。phpはちょっとかじったけど、perlを知ってしまうと、もういいかな、という感じ。 ただphpは後発で、perlにはない良さがなんかあるんだろうな。 動きが軽いとかかな?

最近自分がレンタルしているサーバのアクセスログの、検索語をデコードするスクリプトを書いた。 ごく簡単なものであり、そもそもサポートページでwebalizerを使って表示できる機能がある。 だが、それを自分で書いてみたかった。

その書き方もいろいろあった。logをパースするモジュールもいろいろあるが、それを使わないこともできる。使うのがいいのだろうが、使わなくても簡単にできることがわかった。

モジュールを使わなければできないこともあれば、めんどくさいのでモジュールを使うこともあるし、誰かに教わったやり方がモジュールを使う方法だったから使っているだけだったり、ちょっと考えたらできたから自分で書いたり、エラー処理とか実行速度とかはあまり重要でないからとりあえずできるものでいいからという場合もある。

そして、perlはそのすべてが許される。 それは質問掲示板とかブログとかMLとかにも見られる。「こういう風にやれ、こうするのが通」みたいな思想があまりない。まして、「こうしないとできない」ということはほとんどない。「え!?これでできちゃうの?」と驚くことの連続である。

なかにはperlの書き方について標準的なものを推奨している人がいたりした。たとえば$_は使うなとか。きっと、スクリプトをブツとして納品し、メンテしていくような場合にはそういうものが必要なのだろう。

これはperl以外でも、そしてソースやスクリプトに限らず、試験手順書でも項目でもマニュアルでもなんでも、「標準化」「品質管理」の名の下におこなわれる縛りはほとんど百害あって一利なしである。「プログラミングにはバグがつきものだから管理を厳密にする」これはもう、私には全く受け入れられない。 「ミスのないように気をつける」「チェックをする」「よく確認する」こんなことは、しなくてよい。してはいけない。気をつけなくても、チェックしなくても、確認しなくても、できるようにすること。気をつけて注意して何度もチェックして作ったものは、きっとトランプの塔のように崩れやすく近寄りがたいものになっているだろう。

私がperlで何か書く場合、use strictも使わない。programming perlでは使うことが推奨されていたし、次のバージョン(6?)ではデフォルトで有効になるらしい。だがいちいちmy $nantokaと定義するのはメンド臭い。windowsでactive perlを使うときは最初の行の #!/usr/bin/perlとかも書かない。書き忘れたけど動いたのでそれ以来必要なときしか書かない。ファイルの入力やforeachなどでもなるべく変数を使わないようにしている。インデックスも原則禁止している。そしてそういう「怠惰」さが、結果をよくするのである。そしてその怠惰さは本当は怠惰ではないのである。

わたしはこの業界で感じていた不満と一見いい加減でテキトーに見える自分の仕事のやり方が間違っていなかったことを、perlと出会って確信した。 cでwindowsプログラミングしていたときは、ライブラリがないと何もできなかった。そのくせそのライブラリは自分で苦労して探してもってこないといけない。ほんとうに不親切というかいやがらせのような開発環境だった。 入門書の類は死ぬほどあるしわたしも何冊も買ったがほとんどモノにならない。perlに関してはcよりは少ないと思う。しかも、定番と呼ばれるものがほぼ決まっている。そしてその定番を読んでしばらくすれば、この言語はとても柔軟で人間の考え方にうまく適合することがわかり、何かをするにはどうする、といったハウツー的な情報を探す必要が少ないことがわかる。


#! /usr/bin/perl
use Regexp::Log::Common;
use IO::File;

my $foo = Regexp::Log::Common->new(
    format  => ':extended',
    capture => [qw(host rfc authuser date request status bytes referer useragent)],
);

my $re = $foo->regexp;
my @fields = $foo->capture;

$logfile = $ARGV[0];
open (LOG, $logfile) or die "$!";

while () {
    my %data;
    @data{@fields} = /$re/;
    print 'host: '.@data{'host'}."\n";
    print 'UA: '.@data{'useragent'}."\n";
    print 'request: '.@data{'request'}."\n";
}
close LOG;
ppm install Rexexp::Log::Common
を実行。黙って数十秒待つ。 上記のソースを書く。
use IO::File;
が必須。
@data{@fields} = /$re/;
という行の意味がよくわからないが、リファレンスというやつかな、と、 {}の中にフィールド名を入れてみたら表示された。 なるほど。

しかし、問題はrequestの中の分割なんだよな。 useragentが長い。自分のUAを表示させると150文字くらいある。

日本語にすると、

googlebotかbaiduspiderなら飛ばす。(検索後にこのキーワードが入っていたらそれも飛ばしてしまうがそれはオーライ)
カッコにかこまれた文字列をUseragentとして保存。
グーグルからの検索だったら、検索語を探してデコードする。
まずスペースで区切る。
区切ったものをさらに "?"で区切る。
区切ったものから "q="を含むものを探す。
それをさらに"&"で区切る。
区切ったもののなかで、先頭が"q="であるものを探す。
"q="を消したものを、デコードする。
デコード結果から AND検索の場合に付く"+"を消す。
結果をprintする。
一番最初にスペースで区切ったフィールドのうち、 2個目: 日付 3個目: ホスト さっき保存したUseragentをプリントする。

google以外にも、yahooとbaiduについて同様にして区切り文字のみを変更して対応。 それ以外のサーチエンジンから来たものはログをそのまま表示する。

もし新しいエンジンのものが見つかったら追加していく。 しばらく前はgoogleオンリーだったが、yahooも一日に1,2個くらい混じるようになった。

ログ総数は100もいかない零細サイトなので、日々ログを眺めつつ、改善していく。 

ちなみにここで読んでいるログはあるphpスクリプトが吐いたログで、apacheのログではなかった。ただし、検索ワードのパースだけはできていた。 いい加減主義が結果オーライとなった。