Perlのテク

02/12/25 Naoto Hashimura

現場で秘伝とされているPerlのテクニックです。
この記事を見ている人にコッソリ教えます。

★ファイルの内容を全て読み取る

CGIなどでよくある話で、何かテキストファイル(テンプレートやデータファイルなど)を全部読み込み、加工を施したいという場合があります。

まず一般的な方法。
<> を使い、ファイルを1行ずつ読み取る方法ですが
-------------------------------------------------------------------------------
open(F, "ファイル名");
while(<F>)
{
    # ここで $_ に1行分の文字列が入っている。
    # $_ に対して加工を施す
    ...
}
close(F);
-------------------------------------------------------------------------------
これは1行ずつ読み取って処理しているので遅いのです。

それならread()を使ってガバッと読み、いったん全てを読み込んだ後に加工した方がまだ良さそう。
-------------------------------------------------------------------------------
open(F, "ファイル名");
while(read(F, $readbuf, 1024))
{
    # ここで $readbuf には最大1024byte(1024の値は適当)が入っている。
    $buf .= $readbuf;    # そのまま $buf へくっつける
}
close(F);

# $bufにファイルの全内容がそのまま入っている。
# $bufを加工をするなり何なりと。
-------------------------------------------------------------------------------
秘技!
-------------------------------------------------------------------------------
open(F, "ファイル名");
undef $/;        # <> に改行を認識させなくする
$buf = <F>;      # 全部を一気に読み込む!
close(F);

# $bufにファイルの全内容がそのまま入っている。
# $bufを加工をするなり何なりと。
-------------------------------------------------------------------------------

***

たまにファイルを行ずつ配列へ順にためておきたい場合もあります。
こういう時はやっぱり1行ずつ順に読んでいくしかないか?
-------------------------------------------------------------------------------
open(F, "ファイル名");
while(<F>)
{
    push @buf, $_;
}
close(F);

# @bufにファイルの全内容が1行ずつそのまま入っている。
-------------------------------------------------------------------------------
秘技!
-------------------------------------------------------------------------------
open(F, "ファイル名");
@buf = <F>;
close(F);

# @bufにファイルの全内容が1行ずつそのまま入っている。
-------------------------------------------------------------------------------

★die()を活用

die()ってスクリプトをエラーで死なせるための関数ですが、いきなり死なれても 困る CGIなどで die() は使えるのか?

全然使える! むしろ進んで使いましょう。
ただし、die() を eval{ } で囲んでやります。こうすると死なずに済みます。
-------------------------------------------------------------------------------
eval
{
    open(F, "hogehoge.dat")
      or die("データファイルが開けませんでした\n");

    hogehoge() or die("hogehogeができませんでした\n");

    ...
}
or do
{
    # die() で死んだ時にここへ来る。
    # $@ には die() の文字列が入っている!
    # die() の文字列に \n を付けていない場合、$@ へ行番号や
    # スクリプトのファイル名が追加される。
    # 上の例のように、文字列の最後に \n を付けるとそれらは追加されない。

    chomp($errmsg=$@);    # $@を$errmsg にコピーし、$errmsgの\nを除去

    print "Content-type: text/plain\n\n";
    print "エラー! $errmsg。至急、管理者(045-xxx-xxxx) へ連絡して下さい。";
    exit;

};  # ←ブロックの最後にセミコロンを忘れないように
-------------------------------------------------------------------------------

★ループ処理

配列ループ・各種

・配列の中身を取り出しループ
-------------------------------------------------------------------------------
for(@hoge)
{
    # $_ に配列の要素が入っている
    ...
}

# $_ではなく他の変数へ入れたい場合、
#  for $elem(@hoge) のようにする
-------------------------------------------------------------------------------
・ループのカウントを知りたいループ
-------------------------------------------------------------------------------
for(0..$#hoge)
{
    # $_ に 0から始まる数値が入っている
    # $hoge[$_] として配列の要素を取り出せる
}

# $_ではなく他の変数へ入れたい場合、
#  for $i(0..$#hoge) のようにする
-------------------------------------------------------------------------------
・1から始まるループのカウントを知りたいループ
-------------------------------------------------------------------------------
for(1..@hoge)
{
    # $_ に 1から始まる数値が入っている
    # 1から始まるので、配列のインデックスとして使うには -1 してやる
    # ただループの回数だけ知りたいときはコレ。
}
-------------------------------------------------------------------------------
上2つは、ループ内で1を足すか足さないかだけの違いですが、不精者には重要。
あらゆる方法を駆使してラクをする。


・ハッシュ配列

大抵は each() を使います。
-------------------------------------------------------------------------------
while(($k,$v)=each(%hoge))
{
    ...
}
-------------------------------------------------------------------------------
が! last や return などでこのループを途中で抜けた場合、再び each(%hoge) でループをさせようとすると、 抜けた次から続行してしまいます。 (反復子がリセットされないため)
再び始めからループするには、以前の each() を全部やりきるのみ。
なので、ループを途中で抜けないように注意するか、
1 while(each %hoge);     # ループが終わるまで、何もせず回る
や
keys %hoge;              # これでも反復子はリセットできる
で明示的にリセットさせなければなりません。
要は、途中で絶対にループを抜けない場合や、1回きりしかループをしない場合はこれを使い、 どうなるか分からない場合は次のように keys() で配列ループさせれば安全です。
-------------------------------------------------------------------------------
for $k(keys %hoge)
{
    $v = $hoge{$k};
    ...
}
-------------------------------------------------------------------------------
↑いつもこの形を使えば安全だが、いちいちキーから値を取るのが面倒…



続く・・・



このページの先頭 | 前のページに戻る