このエントリーをはてなブックマークに追加
スポンサーリンク

Perl入門

Perlとは

PerlはC系の言語ですので、書式はC言語にそっくりです。しかし、C言語とは違い、インタプリタ言語なのでコンパイルを必要としません。また変数に直接文字列を代入する、といった高レベル言語ならではの特徴をもっており、C言語に比べて非常にプログラムの作成が楽です。

以前は、常駐プロセスを作るのにCでコンパイルされた実行ファイルが使われる事が多かった(今も多い)のですが、サーバーの性能アップのおかげで今ではPerlでもほとんど事足りるようになりました。

ここでは、Perl言語の初歩を学びましょう。

書式

書式はC言語にかなり似ています。ほとんどを小文字で記述し、セミコロンで区切って書きます。
例)

$kensuu = 0;
while (<IN>) {
   $moji = $_;
   $basho = index( $moji, $kugiri );
   if ($basho != -1 ) {
      ++$kensuu;
   }
}
close (IN);
大文字小文字
Perlは他のC系の言語と同じく、大文字と小文字は区別します。変数名や関数はすべて小文字にするのが一般的です。ただし、定数やファイルハンドルは全て大文字で、モジュール名は頭の1文字目を大文字にするといった風習があります。

インタプリタの指定
プログラムを実行させるためには、perl ファイル名.plみたいに指定しますが、Linux上では1行目にperlへのパスを記述する事で、直接ファイル名を指定すれば実行するようになります。(実行権限は必要です)例えば、

#!/usr/bin/perl

を先頭に入れる事で、直接実行する時に/usr/bin/perlを使ってこのファイルを実行するようになります。

変数

変数は、先頭に$や@や%をつけて変数の種別とともに表記します。C言語のように型を宣言する必要はなく、文字列もそのまま代入できます。変数には、「スカラー変数」と「配列変数」、「ハッシュ変数」があります。スカラー変数とは、つまりは普通の変数の事です。頭に$をつけて表記します。
例)

$a=10; ・・・数値の10が代入される。
$b='abc'; ・・・文字列のabcが代入される。
文字列は、’(シングルクォート)か、"(ダブルクォート)でくくって表します。ダブルクォートの場合は文字列の中に変数を混在させる事ができます。

数値をダブルクォートしても、数値として評価される事があります。例えば、"1"を代入した後、数値の1を足すと、ちゃんと2になります。また、文字変数を足し算する事もできます。たとえば、tk001みたいに、文字と数字がミックスされている文字列に、数値の1を足すと、ちゃんとtk002みたいに、数値の部分が+1されます。また、aという文字を+1すると、bになります。

配列
配列変数は、頭に@をつけて表記します。配列そのものを表す時は、頭に@をつけます。

例)
@hairetu=("a","b","c");

配列の中の1要素を指定する時は、スカラー変数と同じく頭に$をつけます。$a=$hairetu[0];のようにすると、$hairetuの最初の要素である、aが$aに代入されます。配列の添字は0から始まります。

ハッシュ変数
ハッシュ変数は、配列の添字の代わりに、キーワードを使います。ハッシュ全体を現す時は、先頭に%をつけて表します。

例)
%namae=("aufheben","sofoware")

ハッシュの1要素を指定する時は、スカラー変数と同じように頭に$をつけます。また、キーワードは{}でくくります。$a=$namae{"aufheben"};とすると、$aにはsoftwareという文字列が入ります。

ローカル変数とレキシカル変数
ローカル変数は、関数の頭でlocalと宣言して使います。

例)
local $a;

localで宣言すると、擬似ローカル変数になります。グローバル変数の内容がスタックに保存され、関数から抜けると元に戻されます。 なので、関数内でmain::スコープを指定しても、グローバル変数に入っているはずの値は出てきません。 また、localが宣言された関数内でさらに別の関数を呼んでも、そのままそのローカル変数を使う事ができます。(localを宣言した関数が終わるまでスタックに積まれたグローバル変数の値がPOPされないため)

このようなインチキくさいローカル変数が先に作られ、localという予約語を先に使ってしまったため、 のちに真の意味の「ローカル変数」が作られた時には、上位互換を保つためにはもうlocalという予約語が使えないので、仕方なくmyという名前を使っています。

また、「ローカル変数」という名前は先に擬似ローカル変数が使ってしまったため、真のローカル変数はPerlでは「レキシカル変数」と呼びます。 レキシカル変数は、関数の頭でmyと宣言して使います。

例)
my $a;

myで宣言すると、その関数の中だけに使われる領域が確保され、その関数が終わると破棄されます。 また、その関数から他の関数を呼び出した場合、呼び出し先でその変数を使う事はできません。

local宣言の方が先にできたという歴史的な経緯でレキシカル変数という名前になってはいますが(別にそういう意味じゃない?)、 こちらの方が、CやPHPで言うところのローカル変数に近い形になります。 現在では、Perlで「ローカル変数を使う」と言えば、こちらのレキシカル変数を使う事であると言っても良いです。 そのため、変数をローカルにしたい場合、localではなくmyと宣言する人の方が圧倒的に多いです。

演算子

演算子は、C言語と同様、+−*/%が使えます。また、文字変列を連結する場合は、.(ピリオド)を使います。さらに、C言語同様、+=や、*=等を使うこともできます。例えば、 $a+=1とすると、$a=$a+1と同じ意味になります。1を足すだけの場合は、+=1よりも、++と書いたほうが短くなります。
+ 足し算
- 引き算
* かけ算
/ わり算
** べき乗
% あまり
+= 左辺に右辺を加算
-= 左辺から右辺を引く
*= 左辺と右辺をかけて左辺に入れる
/= 左辺から右辺を割った結果を左辺に入れる
.= 左辺を文字列として評価し、右辺を連結する
++ 1を足す
-- 1を引く

比較演算子

比較演算子には、C言語のように<や>があります。 Perlの変数には文字型と数値型の区別はありませんが、変数を文字列として比較する場合と数値として比較する場合では、結果が異なる事があります。PHPではそのために条件判断文の結果が期待通りにならない場合もありますが、Perlでは文字列として評価するか、数値として評価するかを明確に区別しているので、期待通りの結果になります。
意味 数値 文字列
より小さい < lt
より大きい > gt
同じか小さい <= le
同じか大きい >= ge
同じ == eq
違う == ne
比較 <=> cmp
数値として評価するならば、aaaのような英文字列はゼロと評価されます。なので、if ($a==0)とした時に、$aにaaaが入ってると真になります。文字列として評価したい場合は、if ($a eq "0")という風にします。

文字列の、より大きい、より小さいは、左辺から評価していき異なる文字に出会った時にキャラクターコードが大きいかどうかで判別します。なので、10は2より小さいと評価されます。つまり、文字列として評価すると、大小関係は、

1
10
1000
10000
2

となり、数値を文字列として評価した場合には期待通りの大小関係にならない事があります。

年月日のように、桁数のフォーマットが決まってる場合には、文字列としての比較が役に立ちます。この際には、月や日は2桁に揃えておく必要があります。

例)
$a="2007/03/01";
if ($a ge "2007/01/01") {
      :
}

比較(cmp、<=>)は、右辺と左辺が同じか異なるか、またどっちが大きいかを調べる時に使います。等しければ0、左辺が大きければ1、右辺が大きければ-1を返します。文字列として比較する時はcmp、数値として比較する時は<=>を使います。

条件判断

Perlでは条件判断に、C言語でお馴染み、if、while、forが使えるだけでなく、unless、untilも使えるようになっています。
if (条件) {
  文1
} else {
  文2
(条件)が真なら、文1を実行します。偽なら文2を実行します。
unless (条件) {
  文1
条件が偽なら文1を実行します。if文でも代用できますが、『偽であれば実行』という事を明確にしたい時に使います。
while (条件) {
  文1
(条件)が真である間は、文1を実行し続けます。これを利用して、while(1)として無限ループを作り、条件によりlastでループから脱出さる事ができます。ループから抜ける条件が複数ある場合や、ある条件で処理をまとめて飛ばす場合に便利です。
until (条件) {
  文1
whileとは逆に、(条件)が偽である限り文1を実行します。COBOLのPERFORM文のUNTIL句のようなものです。COBOLに慣れた方はこちらの方が良いかもしれません。untilはつまり条件が成立する「まで」という意味です。
for (初期化式 ; 条件 ; 増減式) {
     文1
C言語でもお馴染みの命令で、まず初期化式が実行された後、条件が成立するまで、増減式を実行しながらループします。

なお、CやPHPでは、ループから脱出したり、次のループへ移行したりするのに、breakやcontinueを使いますが、Perlではlastとnextなので混同しないように気をつけましょう。
PHP、C、C++ Perl
ループから脱出 break last
次のループの先頭へ continue next
PHPのように、?演算子を使うこともできます。
(条件) ? 文1 : 文2
条件が真なら文1を、偽なら文2を実行します。if文の省略形として使うことができます。

配列の要素を1個ずつ取り出しながらループする事ができます。
例)
foreach $i (@part) {
   文
配列@partの要素を、1個ずつスカラー変数$iに入れながら、全要素を取り出すまでループします。この場合、$iを省略できます。省略した場合は、$_という変数に入ります。

正規表現

Perlの特徴として、正規表現があります。正規表現とは、文字列を完全一致ではなく、あるパターンにマッチするかどうかで判断したり、あるパターンにマッチしたらマッチした部分だけを置き換えるといった事ができます。

正規表現については、応用編で詳しく説明します。

サブルーチンと関数

Perlで「サブルーチン」は、BASIC言語でいうところの「サブルーチン」と、C言語でいうところの「関数」という2つの考え方の中間のようなものです。Perlでサブルーチンを呼ぶ場合は、サブルーチンという考え方で呼ぶ事も、関数という考え方で呼ぶ事もできます。

サブルーチンという考え方をする
BASC言語では、メインルーチンとサブルーチンという考えがありました。VisualBasicにもその考えが受け継がれ、gosubという命令は残っています。同様に、Perlにもサブルーチンコールの命令があり、呼ぶ場合には頭に&をつけて、サブルーチン名を記述します。
例)

&re_cookie;
この例では、re_cookieというサブルーチンを呼びます。

関数という考え方をする
関数とは、ある引数(引数群)を与えると一定の処理をし、結果を返すものです。
例)

$cookie=re_cookie($a);

この例では、$aを引数にしてre_cookieという関数を呼び、結果を$cookieに返します。

サブルーチンを作る/関数を定義する
Perlでサブルーチンは、最初にsubをつけた後、サブルーチン名を記述します。PHPやJavaScriptのような、functionではありません。perlは歴史的な背景から、サブルーチンという意味あいが強く、宣言もsubになります。C言語のような、リターンコードの型を指定するのは不要です。
例)

sub re_cookie {
  サブルーチン本体
}
サブルーチン内では、myやlocalと宣言しない限りは、変数はグローバル変数が使われます。PHPとは真逆なので、混同しないようにしましょう。
引数を取得する
サブルーチン内で引数を取得する場合、PHPやJavaScriptのような関数名の後ろに引数を記述したりはしません。この辺は関数というよりもサブルーチンという意味あいが強いです。@_という特殊変数(配列)から取り出します。取り出す方法はいくつかあります。

$a=$_[0];
$b=$_[1];

みたいに、1つずつ取り出す事もできますし、

$a=shift @_;
$b=shift @_;

みたいに、配列をシフト命令で頭から1つずつ出すこともできます。この場合、@_は省略できるため、取り出す引数が1つで良い場合は、

$a=shift;

のようにすれば、見た目シンプルになります。

呼び出し元にリターンコードを返す場合は、

return $a;
return 0;

みたいに変数や定数を返すことができます。この辺はサブルーチンというよりは関数という意味合いが強いです。複数のリターンコードが必要な時は、返したい値を$a[0]、$a[1]のように配列に入れておき、

return @a;

みたいにreturn文で配列そのものを指定します。

ファイル

ファイルの読み書きは、C言語に書式は似てますが、FILE構造体などは使わず、ファイルハンドルを使います。C言語やPHPでは、ファイルのオープンモードというのを指定しますが、Perlではファイル名の前に<や>をつけます。
open ファイルハンドル "ファイル名";
ここで、ファイルハンドルは、INやOUTという風に大文字で記述します。大文字で記述しないとエラーになったりしないのですが、慣習としてファイルハンドルは大文字で書くようにしているので、それに合わせる事にします。

ファイル名に <ファイル名 という風に <マークをつけるとINPUT、>マークをつけるとOUTPUTになり、>>マークをつけると、追加書き込みモードになります。さらに、+>と書くと入出力両用モードになります。何もつけなければINPUTになります。INPUTは何もつけない事が多いです。

Perlでは、なるべく短く書けるものは短く書くように作られているので、色々省略できるようになっています。

print OUT <IN>

みたいに単体で書くと、INで開いたファイルをOUTに書き出すという意味になります。

while (<IN>)

みたいにループ命令で書くと『ファイルから1行ずつ読み込んで$_に代入し、終わりまでループする』という意味になります。

ファイルを閉じる時は

close IN;

みたいに書きます。

バイナリファイルを読み出す時は、read() 関数を使います。

read(IN, $buff, 256);
とすると、INから256バイトbuffに読み出します。この場合は、ヌルコードや改行コードに関係なく指定バイトまで読み込みます。バイナリを書き出す場合は、特にバイナリである事を意識せずとも、

print OUT $buff;

で大丈夫です。

ソケットで、タイムアウトの処理などを厳密にやりたい時は、sysread、syswriteを使います。(詳しくは応用編で)

日付

掲示板を作るときなど、日付の取得が重要になってきます。
例)

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
の場合、現在の日付・時刻を、それぞれの変数に代入します。(秒、分、時、日、月、年、曜日、元旦からの日数、サマータイムかどうか)になります。

localtimeの引数は、GMT1970年1月1日午前0時0分0秒から何秒経過してるかどうかを指定しますが、timeと書くことでtime()関数が呼ばれ、GMT1970年1月1日午前0時0分0秒から現在の日本時間(サーバーの設定にもよりますが)まで何秒経過してるかがセットされます。

月は、『0月〜11月』が返ってきますので、実際に使うときは、$mon++とします。また、曜日は0〜6で返ってきますので、

$week = ("日","月","火","水","木","金","土")[(localtime)[6]];

みたいにして、漢字に変換します。これは、localtimeの(6+1)番目の要素(つまり曜日)によって、”日”〜”土”までのいずれかが代入されます。(スライスという)。

年は、西暦から1900を引いた値が入りますので、実際に使うときには1900を足して使います。当初は西暦の下2桁だったのですが、2000年になって00になってしまうとかなりの多くのソフトが誤動作してしまいます。なので、以前は年が90以上なら1900を、90未満なら2000を足すようにしていたのですが(以前このサイトにもそう書いてました)、実際には2000年には年に100が入りました。

なので、90以上なら1900を足すというアルゴリズムでも特に誤動作はしませんでしたが、実際には無条件に1900を足すアルゴリズムで良かったのでした。

分岐

ありません。

C言語でgotoに相当する命令はありません。もともと、分岐命令は不要との声が多いのですが、私個人としてはgotoが使いたくなります。エラーなどで強制的にエラー処理にジャンプさせたい事がよくあるためです。もともと私がBASIC言語やCOBOL言語からこの世界に入った事も影響してるかもしれません。

ただし、Perlではexitやdieを使えば開いていたファイルは自動的にcloseされ、データーベースとの接続はオフになり、トランザクションはロールバックされるため、昔ほどエラーのあと処理にこだわる必要もなくなったと思います。

分岐命令がないので、条件によって長い処理をまるごと飛ばす場合は、その長い処理をif の{ }でくくるか、サブルーチンにしておいて条件合致の場合のみそのサブルーチンをコールする、みたいなアルゴリズムにします。

プログラムの終了

プログラムの終了には、exit;を使います。exitがあるとプログラムは終了し、Linuxであればプロンプトに戻ります。常駐プロセスであれば、常駐が解除されます。

他に、dieという命令で終了させる事ができます。 die ("ファイルの読み込みに失敗しました")と書けば、「ファイルの読み込みに失敗しました」という表示とともに、何行目でそれが発生したかが表示されるので、デバッグが楽になります。また、ソースにdieと書くことで、異常終了の処理だという事が、見てわかりやすくなります。

おわりに

以上でPerlの基本部分の説明を終了します。

他にもPerlにはさまざまな命令、関数があり、特に『短く書けるものは、なるべく短く書く』という思想の上で作られているため、短く書くためのさまざまなテクニックが存在します。筆者は、短く書くよりは可読性を優先するため、あまりそのあたりは詳しくありませんが、極めたいという方は市販のPerl解説本などを参考にしてください。

Perlの特性として追加モジュールや正規表現がありますが、それは応用編で。
スポンサーリンク