Perl入門 ≫ LESSON8 分岐・繰り返し

分岐・繰り返・条件式

Perlでは、プログラム中で処理を分岐したり繰り返したりすることができます。
分岐や繰り返しを行う処理には、条件式が必要になります。
その条件の結果が真なら繰り返しとか、偽なら繰り返しを終了するなど、分岐や繰り返しを行うかどうかの条件です。

この条件式には、主に比較演算子をつかった判定文を使います。
とにかく、展開して真・またはそれ以外かで条件を判定します。

if-else文

もし○○だったら~~~をする、○○でなかったらXXXXをする、というような処理を行うのがif-elseです。いくつか使い方があるので見ていきましょう。

● if (expr1) ブロック形式

if (条件式) {
    処理;
}

もしも条件式が真なら、処理を行います。

my $age = 21;
if ($age >= 20) {
    print "20 over!\n";
}

結果は以下。

20 over!



● if (expr1) ブロック else ブロック形式

if (条件式) {
    処理1;
} else
    処理2;
}

もしも条件式が真なら、処理1を行います。それ以外なら処理2を行います。

my $age = 19;
if ($age >= 20) {
    print "20 over!\n";
} else {
    print "20 under!\n";
}

結果は以下。

20 under!



● if (expr1) ブロック elsif (expr2) ブロック else ブロック形式

if (条件式1) {
    処理1;
} elsif (条件式2) {
    処理2;
} else {
    処理3;
}

もしも条件式1が真なら、処理1を行います。
それ以外でもしも条件式2が真なら処理2を行い、それ以外なら処理3を行います。
elsifブロックは増やせます。

my $age = 19;
if ($age >= 20) {
    print "20 over\n";
} elsif ($age >= 15) {
    print "15 - 19\n";
} elsif ($age >= 10) {
    print "10 - 14\n";
} else {
    print "10 under\n";
}

結果は以下。

15 - 19



● expr1 if expr2;

処理 if 条件式;

もしも条件式が真なら、処理を行います。
条件式の部分は( )でくくってもいいです。

my $age = 21;
print "20 over\n" if $age >= 20;

結果は以下。

20 over



unless-else文

上にある4つの形式は、ifのかわりにunlessを使うこともできます。
unlessとは、ifの否定で条件式が真でなければ処理を行うという意味です。

● unless (expr1) ブロック形式
● unless (expr1) ブロック else ブロック形式
● unless (expr1) ブロック elsif (expr2) ブロック else ブロック形式
● expr1 unless expr2;

ただ、ifを使って条件式に否定の!を付ければ意味は同じなので、混乱しないようわかりやすい条件分岐を書きましょう。

while文

条件式に一致している間処理を繰り返して行う、という繰り返しはwhileを使います。

● while (expr1) ブロック形式

while (条件式) {
    処理;
}

条件式が真の間は、処理を繰り返して行います。

my $i = 0;
while ($i < 5) {
    print "$i\n";
    $i++;
}

結果は以下。

0
1
2
3
4

$iの値が5より小さいときは繰り返しを行います。$iの値はインクリメントしているので、5以上になったら繰り返しを抜けます。



注意

ループ処理を行う場合、プログラムの書き間違いでループが終了せずに無限に繰り返し処理を行ってしまう場合があります。

コマンドプロンプトでいつまでたっても処理が終わらず次のプロンプトが戻ってこなかったり、無間ループに入ってしまったことに気付いたら、すぐにプロンプト画面をアクティブにした状態で、Ctl-C(コントロールキーを押しながらCを押す)をやりましょう。処理が中断できます。



● while (expr1) ブロック continue ブロック形式

while (条件式) {
    処理1;
} continue {
    処理2;
}

条件式が真の間は、処理を繰り返して行います。次のループに入る前にcontinueのブロック処理2を実行します。

my $i = 0;
while ($i < 5) {
    print "$i\n";
    $i++;
} continue {
    print "continue\n";
}

結果は以下。

0
continue
1
continue
2
continue
3
continue
4
continue



● do ブロック while (expr);形式

do {
    処理;
} while (条件式);

最初に必ず一度処理を行います。
処理条件式が真の間は、処理を繰り返して行います。

my $i = 0;
do {
    print "$i\n";
    $i++;
} while ($i < 5);

結果は以下。

0
1
2
3
4



● expr1 while expr2;形式

処理 while 条件式;

条件式が真の間は、処理を繰り返し行います。
条件式の部分は( )でくくってもいいです。

my $i = 0;
print "$i\n" while $i++ < 5;

結果は以下。

1
2
3
4
5



インクリメント、デクリメント

変数をインクリメント、デクリメントして繰り返し判定に使うことが多いです。
何気なく使ってますが、ちょっと注意が必要です。

$i++

は、$iの値を使ってからインクリメントします。
この場合、$i<5と比較してから、$iの値を1プラスしている状態です。
これを、

++$i

とかくと、インクリメントしてから$iの値を使います。
なので、最初の判定のときは$iの値は1になってます。結果は1~4までの出力になります。

print $i++;

の場合は$iの値を出力してからインクリメントしますが、++$iの場合、インクリメントされた値が出力されます。

$i++;のように単体で使う場合はあまり関係ありませんが、他のものと同時に使う場合は注意しましょう。



until文

whileが「○○の間は~を行う」というのに対して、untilは「○○になるまでの間は~を行う」という文になります。

● until (expr1) ブロック形式

until (条件式) {
    処理;
}

条件式が真になるまでの間は、処理を繰り返して行います。

my $i = 5;
until ($i <= 0) {
    print "$i\n";
    $i--;
}

結果は以下。

5
4
3
2
1



● do ブロック until (expr);形式

do {
    処理;
} until (条件式);

最初に必ず一度処理を行います。
処理条件式が真になる間は、処理を繰り返して行います。

my $i = 0;
do {
    print "$i\n";
    $i++;
} until ($i > 5);

結果は以下。

0
1
2
3
4
5



● expr1 until expr2;形式

処理 until 条件式;

条件式が真になる間は、処理を繰り返し行います。
条件式の部分は( )でくくってもいいです。

my $i = 5;
print "$i\n" until $i-- <= 0;

結果は以下。

4
3
2
1
0



for文

○回繰り返す、などと最初から繰り返し回数が決まっているものはforを使うと便利です。

● for (expr1;expr2;expr3) ブロック形式

for (初期化; 条件式; ループ処理) {
    処理;
}

最初に初期化の部分を実行します。
そして、条件式が真の間は処理を繰り返して行います。
一回の繰り返しの最後にはループ処理を行い(大抵変数のインクリメント・デクリメント)条件式を判定してからまた処理を行います。

for (my $i = 0; $i < 5; $i++) {
    print "$i\n";
}

結果は以下。

0
1
2
3
4

$iが0から5より小さい間は繰り返します。
初期化をforの外に出して、ループ処理はブロックの中に含めても同じです。

my $i = 0;
for (; $i < 5;) {
    print "$i\n";
    $i++;
}

ない項目があっても区切りの「;」は忘れないようにしましょう。

● expr1 for list;形式

処理 for リスト;

リスト全てに対して処理を繰り返し行います。

my @list = ('user1', 'user2', 'user3');
print "$_\n" for @list;

結果は以下。

user1
user2
user3



foreach文

配列などのリストの内容に対してすべて順に処理を行いたいときに使うと便利です。

● foreach var (list) ブロック形式

foreach 変数 (リスト) {
    処理;
}

リストのすべての値を一つ一つ変数に代入し処理を行います。
変数を省略した場合、特殊変数$_に入ります。

my @list = ('user1', 'user2', 'user3');
my $usr;
foreach $usr (@list) {
    print "$usr\n";
}

foreach (@list) {
    print "$_\n";
}

結果は以下。

user1
user2
user3
user1
user2
user3



● expr1 foreach list;形式

処理 foreach リスト;

リスト全てに対して処理を繰り返し行います。(expr1 for list;形式と同様)

my @list = ('user1', 'user2', 'user3');
print "$_\n" foreach @list;

結果は以下。

user1
user2
user3



ループ制御

while,until,for,foreachのループブロックでは、プログラムの流れを制御することができます。

制御の前にラベル(label)continueブロックについて説明しましょう。
プログラム中の各場所に

ラベル名: while ..

という形式でラベルを付けることができます。
そこに移動せよ!と制御することができるのですが、あまり使わない方がいいかもしれません。 使わなくても問題ありません。
注)ラベルはループに限らずプログラム中どこでも使えます。

● goto label

goto ラベル名;

ラベル名 : 処理

ラベルの位置に処理を移します。
これはループではない場所でも有効です。

print "1\n";
goto label1;
print "2\n";
label1 : print "3\n";

結果は以下。

1
3



● last [label]

last [ラベル名];

ループを終了します。continueブロックは実行しません。
ラベル名があれば、ラベルのループに対して終了します。 ラベル名を省略すると、最も手前(最近)ループを終了します。

my $i = 0;
while ($i < 100) {
    print "$i\n";
    $i++;
    if($i >= 5) { last; }
}

$i = 0;
label1 : for(my $j = 0; $j < 10; $j++) {
    while ($i < 10) {
        print "$j $i\n";
        $i++;
        if($i >= 5) { last label1; }
    }
}

結果は以下。

0
1
2
3
4
0 0
0 1
0 2
0 3
0 4



● next [label]

next [ラベル名];

すぐにcontinueブロックを実行し、次のループを実行します。
ラベル名があれば、ラベルのループに対してnextを実行します。 ラベル名を省略すると、最も手前(最近)のループに対してnextを実行します。

my $i = 0;
while ($i < 7) {
    $i++;
    if($i >= 5) { next; }
    print "$i\n";
} continue {
    print "continue\n";
}

結果は以下。

1
continue
2
continue
3
continue
4
continue
continue
continue
continue



● redo [label]

redo [ラベル名];

条件を評価せずに次のループを実行します。continueブロックは実行しません。
ラベル名があれば、ラベルのループに対してredoを実行します。 ラベル名を省略すると、最も手前(最近)のループに対してredoを実行します。

my $i = 0;
while ($i < 7) {
    $i++;
    print "$i\n";
    if($i >= 7) { last; }
    if($i >= 5) { redo; }
} continue {
    print "continue\n";
}

結果は以下。

1
continue
2
continue
3
continue
4
continue
5
6
7



論理演算子

条件式が複数ある条件、全ての条件を論理演算子でつないで、その結果を全体の判定結果とします。

論理演算子
a && b論理 AND
a,bともに真なら真・それ以外は偽
a and b論理 AND
a,bともに真なら真・それ以外は偽
a || b論理 OR
a,b少なくともどちらか一方が真なら真・それ以外は偽
a or b論理 OR
a,b少なくともどちらか一方が真なら真・それ以外は偽

&&とand、||とorはそれぞれ同じです。が、優先順位はそれぞれandとorのほうが低いです。&&と||よりもandとorの方が推奨されています。


● (expr1) && (expr2)

条件がすべて真ならば真、それ以外は偽になります。

for(my $age = 0; $age < 5; $age++) {
    print "$age ";
    if (($age >= 2) && ($age < 4)) {
        print "2-4\n";
    } else {
        print "else\n";
    }
}

結果は以下。

0 else
1 else
2 2-4
3 2-4
4 else



● (expr1) || (expr2)
条件がどちらか一つでも真なら真、それ以外は偽になります。

for(my $age = 0; $age < 5; $age++) {
    print "$age ";
    if (($age == 2) || ($age == 4)) {
        print "2 or 4\n";
    } else {
        print "else\n";
    }
}

結果は以下。

0 else
1 else
2 2 or 4
3 else
4 2 or 4


条件付き実行

論理演算子を使うと、その先の処理をするかしないか処理を分岐することができます。

○ expr1 && expr2;
&&は条件がすべて真ならば真なので、最初の文が真なら次の文も実行します。 (最初の文が偽ならば全体は偽と決まってしまうので、次の文は実行する必要はありません)

my $i = 1;
$i && print "\$i true\n";

結果は以下。

$i ture



○ expr1 || expr2;
||は条件が少なくとも一つ真ならば真なので、最初の文が真ならば次の文は実行しません。 偽の場合は実行します。 (最初の文が真ならば全体は真に決まってしまうので、次の文は実行する必要はありません)

my $i = 1;
$i || print "\$i true\n";

結果は何も出力しません。

○ expr1 ? expr2 : expr3;
最初の文が真ならばexpr2を、偽ならばexpr3を実行します。if-elseと同様。

my $i = 0;
$i ? print "\$i true\n" : print "\$i false\n";

結果は以下。

$i false



その他の繰り返し

上記以外の繰り返し記述方法を紹介します。

● (expr1) x (expr2)
x・・掛け算の意味なのでしょうか?詳しくはわかりませんが、xの左の処理を右の回数分繰り返すことができます。

print 'A' x 10;

結果は以下。

AAAAAAAAAA



● (expr1) .. (expr2)
範囲演算子と言って、”..”の左から”..”の右までの範囲を繰り返すことができます。

for (0 .. 9) { print; }

結果は以下。

0123456789

この場合は、0から9までという意味になるので、0から9までの数字が順次リストとなってfor文で実行されます。
この辺の詳しい事は、正規表現の部分で学習しましょう。

ページのトップへ戻る