[ ↑ INDEX ] [ ← PREV ] [ NEXT → ]

Lesson 5 真偽値,返り値,比較演算子,論理演算子


■1. 真偽値

Perl では,未定義値・数値の 0・文字列の "0"・空の文字列 "" は「偽」,その他は「真」と判断される。

数値の 00.0 なども数値としては 0 と同じなので,0.0 も偽となる。
文字列の "0""0.0" は文字列としては "0" とは異なるので "0.0" は真となる。
空の文字列値が定義されていないのではなく,値が空の文字列であるということ。未定義値との違いに注意。
未定義値値が定義されていないもの,あるいは undef によって未定義値とされたもの。

if, while などの条件の指定に式や変数などを書いた場合,真偽 (成立・不成立) は,その条件を評価したときに返される値 (返り値,戻り値) により決まる。例えば,m 演算子を用いてマッチングを行うと,成功すれば真 (1) を,失敗すれば偽 ("") を返す。s 演算子の場合は,置換に成功すれば置換した数を返すので,置換に成功すれば真 (1, 2, 3, ...) となり,成功しなければ偽 ("") となる。

上の説明は,スカラーコンテキストでの話。コンテキストについては Lesson 7 で説明する。

◇ スクリプトの実行

次のスクリプトの条件部分 (1) を変えて,どのようなものが真と判断され,どのようなものが偽と判断されるか確認しなさい。(else については,ここを参照。)

   % perl -e 'if (1) { print "TRUE\n"; } else { print "FALSE\n"; }'

       1. 0             10. "John"
       2. 0.0           11. $var
       3. "0.0"         12. undef
       4. ""            13. length "John"
       5. " "           14. length ""
       6. "\n"          15. $var = "John"
       7. 1 - 1         16. $var = ""
       8. "1 - 1"
       9. 0.5

■2. 比較の演算子

Perl では,各データは数値としての値と文字列としての値を持つ。"4.0" と "4" は数値としては等しいが,文字列としては等しくない。データを比較するには,数値として比較するのか,文字列として比較するのかを区別し,それぞれに対して異なる演算子を用いなければならない。

 数値文字列返り値
A は B と等しい A == B A eq B成立すれば 1,
しなければ偽 ("")
A は B と等しくない A != B A ne B
A は B より大きい A > B A gt B
A は B 以上 A >= B A ge B
A は B より小さい A < B A lt B
A は B 以下 A <= B A le B
A と B を比較 A <=> B A cmp BA が B より
大きければ 1,
小さければ -1,
等しければ 0

文字列の大小の比較は文字コード上の順序を基に行う。文字コード上,後ろにあるものが前にあるものより大きい。大文字はすべて小文字よりも前に配列されているので,Za より「小さい」。大文字小文字を区別せずに比較するには,lc, uc などを使い,どちらかに揃えてから比較する。

   if (lc "ABC" eq  lc "abc") { ... }
   if (uc $var1 cmp uc $var2) { ... }

比較演算子 == と代入演算子 =

=== は間違いやすいので気をつけること。

== は左辺と右辺を比較し,数値として等しければ真 (1),等しくなければ偽 ("") を返す演算子。

= は右辺の値を左辺の変数に代入する演算子で,代入した値が返り値となる。空の文字列と 0 (数値としての 0,あるいは文字列の "0") が代入された場合を除き,真となるため,while の条件を指定する際に,== と間違えて = を使うと,無限ループを作ってしまうので要注意。

文字列比較 (A eq B) とパターンマッチ (A =~ /B/)

A eq B と A =~ /B/ も混乱しやすいので,違いを確認しておくこと。

 "abc" eq "a"   "abc" ne "a"  
 "abc" =~ /a/   "abc" !~ /a/  
 "abc" =~ /^a$/   "abc" !~ /^a$/  

■3. 論理演算子: and, &&, or, ||, not, !

and (&&), or (||), not (!) は,それぞれ「論理積」「論理和」「否定」の演算子である。

A and B は,A・B ともに真のとき真,それ以外は偽となる。A or B は A・B のどちらかが真であれば真,ともに偽のときに偽となる。not A は A が真のとき偽,偽のとき真となる。

ABA and BA or Bnot A
          
          
          
          

これら論理演算子を使って複数の条件を組み合わせることで,複雑な条件が指定できるようになる。

and&&or||not! には優先順序の違いがある。どちらも,後者の方が優先順序が高い。

優先順位が不明な場合には,( ) で括って結合の順番を明示的に指定するとよい。下の 1 と 2 は ( ) の付け方が違うだけだが,表わしていることは異なる。

   1. (A or B) and (C or D)
   2. A or (B and C) or D

論理演算子を利用した条件の指定

・A or B

A or B はどちらか一方が真ならば真となる。Perl では,A が真であれば B の真偽に関係なく A or B が真となるため,B の評価を行わない。これを利用して,A が成立しなかったときだけ B を行うのに or, || が使われることがある。

   #ファイルを開く。開けなければスクリプトを終了する。
   open (IN, "input.txt") or die "Cannot open the file\n"
open は成功すると真を,失敗すると偽を返す。die は引数で指定したエラーメッセージを表示してスクリプトを終了する関数。引数は省略可。

次のように書くと,変数 $var の値が未定義・数値の 0・文字列の "0"・空の文字列 "" の場合,50 が代入される。例えば,値が指定されなかったときのデフォルトを指定するのに使える。(演算子の優先順位の関係で,二つ目のものには ( ) が使われている。)

   $var or  $var = 50
   $var || ($var = 50)

        cf. $var = 50 if ! $var;
            $var = 50 unless $var;

$var || ($var = 50) は次のように書くこともできる。

   $var ||= 50

・A and B

A and B の場合は両方とも真でなければ真とはならないので,A が偽であれば,B の評価を行わない。これを利用して,A が成立したときだけ B を行うのに and, && が使われる。

   #ファイルを開く。開ければ1レコード $data に読み込む
   open (IN, "input.txt") and $data = <IN>

■4. 返り値

これまで学んだ関数・演算子には,length, lc, substr のように対象自体は何の変化も受けず,関数・演算子が返す値を利用するものと,chop, chomp, s/// などのように対象に対して何らかの作用を及ぼすものとがあった。

chop, chomp, s/// などの関数・演算子は,対象に対してある操作をする。したがって,単に次のように書けば,対象が変化する。

   chop $str;
   chomp $str;
   $str =~ s/Japan/<<$&>>/g;

副作用として返り値を返すので,それを利用したければ,変数に代入するなどの処理をする。

   $var = chop $str;                 #$var には削除された文字が代入される
   $var = $str =~ s/Japan/<<$&>>/g;  #$var には置換の回数が代入される

これに対し,length, lc, substr などは,ある値を返すのが主作用で,引数として指定された対象そのものは変化を受けない。したがって,次の処理は (それだけでは) 無意味な処理である。

   length $str;
   lc $str;
   substr ($str, -25);

返す値を利用するために使う関数なので,返り値を変数に代入したり,何かと比較したりなど,値を返すことに意味がある文脈で使う。

   $var = length $str;            #$str の文字数を $var に代入
   if (1 <= length $str) { ... }  #$str に何か文字があれば処理を行う
   if (length $str) { ... }       #$str  〃
   print length $str;             #$str の文字数を出力する

lc は「対象文字列を小文字に変換した文字列を返す」関数である。これを誤って「対象文字列を小文字にする」関数と考えてしまうと,lc $str としただけで,$str の内容が小文字に変換されたような錯覚に陥るので注意すること。$str の内容を書き換えるには次のようにする。

   $str =  lc $str;
   $str =~ tr/A-Z/a-z/;

[ ↑ INDEX ] [ ← PREV ] [ NEXT → ]