ぱかぽこお馬さんPumpkinNet
 わいわいコミュニケーションネットワーク 
PumpkinNet CGI工房へようこそ。
Perl基礎講座(4)


CGI工房ホーム
スクリプト講座ホーム
CGIってなに?

(Introduction)
Perlをゲットしよう!
基礎講座(1)
変数の扱い
基礎講座(2)
制御構造文 if
基礎講座(3)
変数の複数形(1)
基礎講座(4)
ループの処理
基礎講座(5)
変数の複数形(2)
Perl基礎講座(4)
繰り返し処理 -ループについて-

繰り返し処理、ループってなんでしょう?

同じ条件式を何度も繰り返したい時などに使います。

もうちょっと噛み砕いて説明します。
構造がこのようなデータ配列 @address を作成したとします。
idusernameaddress
1なむことうきょうとなんとか市
2こなみおおさかけん
3じゃれこさいたまけん
これを、id,username,addressを順々に読み出して表示させたい!というような場合
1つの処理ルーチンをまず作って、それをループで繰り返せばよいわけです。
やろうと思えばループを使わなくても処理ができますが、このような「ブロック」にまとまられるものは
効率からいって、ループを使うのがよいでしょう。

さて、ちょっと話が横にそれますが、このデータは固定長でしょうか、可変長でしょうか。
固定長というのは「ある一定の長さ」をデータの項目ごとに決めておく方法です。
可変長というのは「長さは固定でなく」データを区切り文字で区切って
識別します。
固定長はデータベースを使っていて、きっちりと構築をしている方には御馴染ですね。
一般的なCGIでは可変長のデータ構造です。理由は簡単だから(笑)

ということで、先ほどのデータベース配列 @addressは 各々のデータを区切り文字「,」
で区切ってあるということにします。
さて、では配列@addressを作りましょう。
@address = (
	"1,なむこ,とうきょうとなんとか市",
	"2,こなみ,おおさかけん",
	"3,じゃれこ,さいたまけん"
);
この区切り文字ごとで、データをsplit(分割)するには..そう、split
というコマンドを使います。
前編の基礎講座3で書いたように、配列は それぞれのindexで呼び出すことができました。
$address[0]とすると、配列の最初のデータでしたね?
splitはこんな風に書きます。
($id,$username,$address) = split(/,/,$address[0]);
さあ、じゃあ表示させてみましょうか。
kiso4_1.plとして保存して、実行してみてください。
@address = (
	"1,なむこ,とうきょうとなんとか市",
	"2,こなみ,おおさかけん",
	"3,じゃれこ,さいたまけん"
);
($id,$username,$address) = split(/,/,$address[0]);
print "id NO: $id\n";
print "user : $username\n";
print "address: $address\n";
exit;
実行結果

うまく表示されましたね?

さて、では この処理を、配列全部に対してループで処理できるようにしてみましょう。

kiso_4_2.pl
@address = (
	"1,なむこ,とうきょうとなんとか市",
	"2,こなみ,おおさかけん",
	"3,じゃれこ,さいたまけん"
);
foreach $i (@address) {
	($id,$username,$address) = split(/,/,$i);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
exit;
さあ、実行結果はいかに?

foreach というループ制御のブロックで、splitをして、printを繰り返しています。
これで、先頭から最後まで自動的にループしてくれるわけです。

Perlではループの処理に、4つのコマンドを持っています。
while
until
for
foreach
です。
whileは条件式が真(TRUE)であればループします。
while ($length < 1000) { 
	loopさせたいコマンド;	#ここで$lengthが条件式に合致しない値になることで
	$length の処理;		#ループが終了する。
}
$length よりも 1000が大きければ、ループが実行される、ということです。

untilは whileの逆、条件式が偽(FALSE)であればループします。
until ($length < 1000) { 
	loopさせたいコマンド;
	$length の処理;		#ここで$lengthが条件式に合致しない値になることで
				#ループが終了する。
}
$length よりも 1000が大きくなかったらループが実行される、ということです。

forループ
Cを使っていた人にはおなじみですね。
for (初期式; 条件式; 加減式) {
	loop中の命令;
}
と書きます。
実際にはこうなります。先ほどのforeach と同じように @addressを全部処理させるには
for ($i=0; $i < @address; $i++) {
	($id,$username,$address) = split(/,/,$address[$i]);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
と、なります。
$i と @addressを比較しているので、ン!?と思う方もいらっしゃるかもしれません。
配列は、スカラーコンテキスト内で評価をすると、配列の要素数を返すんです。
気になる方は、この処理の前に要素数を入手してからやっても構いません。
$addcount = @address;	#配列の要素数を変数addcountへ代入
for ($i=0; $i <= $addcount; $i++) {
	($id,$username,$address) = split(/,/,$address[$i]);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
foreachは、forと似ているものですが、配列の処理の時に便利です。
配列をループ時に自動的に変数へ展開してくれるので、
$address[$i]というような、配列のindexを指定してやらなくて済むのです。
foreach (@address) { }
foreach $i (@address) { }
の2つはほぼ、同じことをしています。
違いは変数の指定を明示的にしているか、いないかのみです。
foreach $i (@address)
とすると、配列@addressの内容を$iにコピーをしながら、ループが実行されます。
明示的に変数を指定しなければ、特殊変数 $_ が使われます。

明示的な変数指定のforeach ループ
foreach $i (@address) {
	($id,$username,$address) = split(/,/,$i);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
明示的な変数を指定しないforeach ループ
foreach (@address) {
	($id,$username,$address) = split(/,/,$_);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
foreachには、一つ注意しておくことがあります。
要素を変数に展開していますが、この変数の内容を書き換えた場合
自動的に、その配列の内容も書き換わるのです。
覚えておきましょう。

さて、whileでも同じように、配列をそのままループすることができます。
ですが、foreachと同じように考えてはいけません。
配列 @addressの内容に全く手を触れなければ
@addressはいつまでもデータがある状態=TRUEである。からです。
whileを使って配列を処理したい場合は、
@address = (
	"1,なむこ,とうきょうとなんとか市",
	"2,こなみ,おおさかけん",
	"3,じゃれこ,さいたまけん"
);
while (@address) {
	$i = shift(@address);	#@addressの一番上のデータを変数$iに移す
	($id,$username,$address) = split(/,/,$i);
	print "id NO: $id\n";
	print "user : $username\n";
	print "address: $address\n";
}
exit;
このようにするとうまくいきます。
shiftで値を削って、変数$iに移すことで、配列が空の状態を作りだすことができ、
データがなくなると同時に、ループが終了します。

なお、式条件が合致しなければ、一度もループが実行されないで次に処理が流れます。

ループを途中で止める?

while,until,for,foreachの処理中、ある条件に合致したら、即座にループを抜ける
または、ある条件に合致したら、ループ制御内にあるコマンドを実行しないで、
再ループすることができます。
kiso4_3.plとして保存して、実行してみましょう。
$a=0;
for(;;) {
	$a++;	#インクリメント 1ずつ自動的に加算される
	if ($a == 10) { next; }	#変数aが10になったら下に流れず再ループ
	elsif ($a == 15) { last; } #変数aが15になったらループを抜ける
	print "now loop count $a\n";
}

ループの最初で $aに1ずつ加算して、if〜elsif、その後printしています。
まず、count 10が画面に表示されていませんね?
最初のif文では、$a == 10 となっています。
$aが10の時、nextという命令が実行されます。
ここで、下の命令へプログラムが流れることなく、次のループが実行されています。

次にelsif。$a == 15。 14まで表示されて、プログラムが終了していますね?
変数$aが15になったら、elsif文がtrueになるので、lastという命令が実行され、
ループが終了するのです。

ループ内の下の命令へ流れさせないで、次のループを開始させるのがnext
ループ内の下の命令へ流れさせないで、即座にループを停止するのがlast
です。おぼえておきましょう。

なお、先ほどのfor(;;) は無限ループの指示です。
ループ内に、きちんとした制御文(lastで抜ける)のを入れるのを忘れずに。
whileでの無限ループは 0が偽(FALSE)で、1以上なら真(TRUE)
while(1) などと書くことで、whileで無限ループできます。

さて、では次は配列(2)の予定です。


CGI工房 ホーム  更新履歴  掲示板系  チャット系  メール系  その他スクリプト  スクリプト講座  情報交換BBS
ご意見・ご要望は掲示板もしくは、メールにて:info@pumpkinnet.to

Copyright (C) 1986〜2004 Pumpkinnet All Rights Reserved
PumpkiNet-MiniBanner