演算子の優先順位
|
[SYNOPSIS] [DESCRIPTIONS] [アロー演算子] [インクリメントとデクリメント] [指数演算子] [単項演算子] [拘束演算子] [乗法演算子] [加法演算子] [シフト演算子] [名前付き単項演算子] [比較演算子] [等価演算子] [ビットごとの AND] [ビットごとの OR と XOR] [C スタイルの論理積] [C スタイルの論理和] [範囲演算子] [条件演算子] [代入演算子] [リスト演算子 (右方向)] [論理否定] [論理積] [論理和と排他論理和] [Perl にない C の演算子] [クォートとクォートのような演算子] [I/O 演算子] [定数の畳み込み] [整数演算] |
左結合 項 リスト演算子 (左方向に対して) 左結合 -> 非結合 ++ -- 右結合 ** 右結合 ! ~ \ 単項の+ 単項の- 左結合 =~ !~ 左結合 * / % x 左結合 + - . 左結合 << >> 非結合 名前付き単項演算子 非結合 < > <= >= lt gt le ge 非結合 == != <=> eq ne cmp 左結合 & 左結合 | ^ 左結合 && 左結合 || 非結合 .. 右結合 ?: 右結合 = += -= *= などの代入演算子 左結合 , => 非結合 リスト演算子 (右方向に対して) 左結合 not 左結合 and 左結合 or xor以下の節では、これらの演算子を優先順位に従って紹介します。
@ary = (1, 3, sort 4, 2); print @ary; # 1324 と印字では、sort の右のコンマは sort よりも前に評価されます (右側 から見ると sort の優先順位が低い) が、左側のコンマは sort の あとに評価されます (左側から見ると sort の方が優先順位が高く なっている)。
# 以下は print を行なう前に exit を評価します: print($foo, exit); # 明らかにやりたいことではないでしょう。 print $foo, exit; # これでもない。 # 以下は exit を評価する前に print を行ないます: (print $foo), exit; # これがしたかった。 print($foo), exit; # これでもいい。 print ($foo), exit; # これも OK。また、
print ($foo & 255) + 1, "\n";の動作を一目見ただけで判断するのは、難しいでしょう。
print ++($foo = '99'); # '100' と印字 print ++($foo = 'a0'); # 'a1' と印字 print ++($foo = 'Az'); # 'Ba' と印字 print ++($foo = 'zz'); # 'aaa' と印字デクリメント演算子には、マジカルなものはありません。
chdir $foo || die; # (chdir $foo) || die chdir($foo) || die; # (chdir $foo) || die chdir ($foo) || die; # (chdir $foo) || die chdir +($foo) || die; # (chdir $foo) || dieですが、* は chdir や rand よりも高い優先順位となっているの で:
chdir $foo * 20; # chdir ($foo * 20) chdir($foo) * 20; # (chdir $foo) * 20 chdir ($foo) * 20; # (chdir $foo) * 20 chdir +($foo) * 20; # chdir ($foo * 20) rand 10 * 20; # rand (10 * 20) rand(10) * 20; # (rand 10) * 20 rand (10) * 20; # (rand 10) * 20 rand +(10) * 20; # rand (10 * 20)となります。
$home = $ENV{'HOME'} || $ENV{'LOGDIR'} || (getpwuid($<))[7] || die "You're homeless!\n";のようにすることができます。 Perl では、多少読みやすい && と || の同義語として、 "and" 演 算子と "or" 演算子が用意されています (下記参照)。
unlink "alpha", "beta", "gamma" or gripe(), next LINE; C スタイルの演算子では: unlink("alpha", "beta", "gamma") || (gripe(), next LINE);のように書く必要があります。
for (1 .. 1_000_000) { # プログラム }のようなことを書くと、メモリを使い果たして、悲惨な結果になり かねませんので注意してください。 スカラコンテキストで使われたときには、 ".." はブール値を返し ます。
if (101 .. 200) { print; } # 101 行目から 200 行目を印字 next line if (1 .. /^$/); # ヘッダをスキップし、 s/^/> / if (/^$/ .. eof()); # 本文を引用する。リスト演算子として:
for (101 .. 200) { print; } # $_ を 100 回、印字する @foo = @foo[$[ .. $#foo]; # コストがかかるが何もしない @foo = @foo[$#foo-4 .. $#foo]; # 最後の 5 要素のスライス(リストコンテキストでの) 範囲演算子は、被演算子が文字列であ るときには、マジカルインクリメントの機能を使います。
@alphabet = ('A' .. 'Z');と書けますし、
$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];と書けば、16 進の数字が得られますし、
@z2 = ('01' .. '31'); print $z2[$mday];とすれば、0 付きの日付が得られます。
($a_or_b ? $a : $b) = $c;このことがプログラムの読みやすさにつながるかどうかは、別問題 なので注意してください。
$a += 2;は、
$a = $a + 2;と等価ですが、tie() のようなもので起こる左辺値の被参照による 副作用が 2 回起こることはありません。
**= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=グループ分けしてありますが、これらはいずれも代入演算子として 同じ優先順位となっています。 C と違って、代入演算子は有効な左辺値を作り出します。
($tmp = $global) =~ tr [A-Z] [a-z];のように何かのコピーを変更したいときに便利です。
($a += 2) *= 3;は、
$a += 2; $a *= 3;と等価となります。 二項演算子の "," はコンマ演算子です。
open HANDLE, "filename" or die "Can't open: $!\n";「リスト演算子 (左方向)」の節の記述も参照してください。
通常記法 | 汎用記法 | 意味 | 展開 |
---|---|---|---|
'' | q{} | リテラル | 不可 |
"" | qq{} | リテラル | 可 |
`` | qx{} | コマンド | 可 |
qw{} | 単語リスト | 不可 | |
// | m{} | パターンマッチ | 可 |
s{}{} | 置換 | 可 | |
tr{}{} | 変換 | 不可 |
\t タブ \n 改行 \r 復帰 \f 改ページ \v 垂直タブ (それが何であっても) (訳注: これは使えないように見える) \b バックスペース \a アラーム (ベル) \e エスケープ \033 8 進数で表した文字 \x1b 16 進数で表した文字 \c[ コントロール文字 \l 次の文字を小文字にする \u 次の文字を大文字にする \L \E まで小文字にする \U \E まで大文字にする \E 変更の終わり \Q \E まで正規表現のメタ文字をクォートするパターンはさらに、正規表現として展開が行なわれます。
g グローバルにマッチ、つまり、すべてを探し出す i 大文字、小文字を区別しない m 文字列を複数行として扱う o パターンのコンパイルを 1 度だけにする s 文字列を単一行として扱う x 拡張正規表現を使用するがあります。 区切文字が "/" のときには、最初の m は付けても付けな くてもかまいません。
open(TTY, '/dev/tty'); <TTY> =~ /^y/i && foo(); # 要望により foo を実行 if (/Version: *([0-9.]*)/) { $version = $1; } next if m#^/usr/spool/uucp#; # 安上がりな grep $arg = shift; while (<>) { print if /$arg/o; # 1 度だけコンパイル } if (($F1, $F2, $Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/))最後の例は、$foo を最初の 2 つの単語と行の残りに分解 し、$F1 と $F2 と $Etc に代入しています。
# リストコンテキスト ($one,$five,$fifteen) = (`uptime` =~ /(\d+\.\d+)/g); # スカラコンテキスト $/ = ""; $* = 1; # Perl 5 では、$* は使わないほうがよい while ($paragraph = <>) { while ($paragraph =~ /[a-z]['")]*[.!?]+['")]*\s/g) { $sentences++; } } print "$sentences\n";
$foo = q!I said, "You said, 'She said it.'"!; $bar = q('This is it.');
$_ .= qq (*** The previous line contains the naughty word "$1".\n) if /(tcl|rexx|python)/; # :-)
$today = qx{ date };詳しくは「I/O 演算子」の節を参照してください。
split(' ', q/STRING/);と完全に同じになります。 よく行なわれる例としては:
use POSIX qw( setlocale localeconv ) @EXPORT = qw( foo bar baz );というものがあります。
オプションには、 e 式の右側の評価を行なう g グローバルな置換、つまり見つかったものすべて i 大文字、小文字を区別しないで検索 m 文字列を複数行として扱う o パターンのコンパイルを 1 度だけにする s 文字列を単一行として扱う x 拡張正規表現を使用する があります。英数字、空白ではない任意の区切り文字で、スラッシュを 置き換えることができます。
例: s/\bred\b/mauve/g; # winterred は変更しない $path =~ s|/usr/bin|/usr/local/bin|; s/Login: $foo/Login: $bar/; # 実行時パターン ($foo = $bar) =~ s/this/that/; $count = ($paragraph =~ s/Mister\b/Mr./g); $_ = 'abc123xyz'; s/\d+/$&*2/e; # 'abc246xyz' となる s/\d+/sprintf("%5d",$&)/e; # 'abc 246xyz' s/\w/$& x 2/eg; # 'aabbcc 224466xxyyzz' s/%(.)/$percent{$1}/g; # パーセントエスケー # プを変更; /e なし s/%(.)/$percent{$1} || $&/ge; # 式となるので /e s/^=(\w+)/&pod($1)/ge; # 関数呼び出しを使う # /e はネスト可能; # $_ に単純に埋め込まれた変数を展開する s/(\$\w+)/$1/eeg; # C コメントの削除 $program =~ s { /\* (?# 開始区切り文字にマッチ) .*? (?# 最短一致でマッチ) \*/ (?# 終了区切り文字にマッチ) } []gsx; s/^\s*(.*?)\s*$/$1/; # 空白の切り詰め s/([^ ]*) *([^ ]*)/$2 $1/; # 最初の 2 語の入れ替え最後の例で \ の代わりに $ を使っているのに注意してく ださい。
2 つ例を示します: # 整数の適切な位置にコンマを入れる 1 while s/(.*\d)(\d\d\d)/$1,$2/g; # perl4 1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/g; # perl5 # タブを 8 カラムのスペースに展開 1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e; tr/SEARCHLIST/REPLACEMENTLIST/cds y/SEARCHLIST/REPLACEMENTLIST/cds検索リスト (SEARCHLIST) に含まれる文字を、対応する置 換リスト (REPLACEMENTLIST) の文字に変換します。
例: $ARGV[1] =~ tr/A-Z/a-z/; # 小文字に統一 $cnt = tr/*/*/; # $_ 内の * を数える $cnt = $sky =~ tr/*/*/; # $sky 内の * を数える $cnt = tr/0-9//; # $_ 内の数字を数える tr/a-zA-Z//s; # bookkeeper -> bokeper ($HOST = $host) =~ tr/a-z/A-Z/; tr/a-zA-Z/ /cs; # 英字以外を 1 つの # スペースに変換する tr [\200-\377] [\000-\177]; # 8th bit 目を削除変換テーブルはコンパイル時に作られるので、SEARCHLIST も REPLACEMENTLIST もダブルクォート展開の対象とはな りません。
eval "tr/$oldlist/$newlist/"; die $@ if $@; eval "tr/$oldlist/$newlist/, 1" or die $@;
while ($_ = <STDIN>) { print; } while (<STDIN>) { print; } for (;<STDIN>;) { print; } print while $_ = <STDIN>; print while <STDIN>;STDIN、STDOUT、STDERR というファイルハンドルは、あらかじめ定 義されています。
while (<>) { ... # 行ごとの処理 } というループは、 unshift(@ARGV, '-') if $#ARGV < $[; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # 行ごとの処理 } } のような Perl の擬似コードと等価です。わずらわしく書かなく ても、動作します。
while ($_ = $ARGV[0], /^-/) { shift; last if /^--$/; if (/^-D(.*)/) { $debug = $1 } if (/^-v/) { $verbose++ } ... # その他のスイッチ } while (<>) { ... # 個々のファイルに対するコード }
のようなループを置くこともできます。
シンボル <> が「偽」を返すのは一度きりです。
偽となったあと で、もう一度呼び出すと、新たに別の @ARGV を処理するものとみ なされ、その時に @ARGV を設定しなおしていないと、STDIN から 読み込むことになります。 山括弧の中の文字列が (<$foo> のような) スカラ変数の参照とな っていれば、その変数が入力を行なうファイルハンドルの名前を示 しているとみなされます。 山括弧の中の文字列がファイルハンドルでなければ、グロブを行な うファイル名のパターンと解釈され、コンテキストによって、ファ イル名のリストか、そのリストの次のファイル名が返されます。 まず、1 段階だけ $ の展開が行なわれますが、前の段落に書いた 間接ファイルハンドルと同じになる、<$foo> のようには書けませ ん。
ファイル名グロブと解釈させるには <${foo}> のように中括 弧を入れる必要があります。
(別の方法として、glob($foo) と内 部関数を呼ぶこともできます。
おそらく、まず、こちらの方で試 すのが正解でしょう。)
例: while (<*.c>) { chmod 0644, $_; } は、 open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|"); while (<FOO>) { chop; chmod 0644, $_; }と等価です。
chmod 0644, <*.c>;と書けます。 グロブはシェルを呼び出しますから、自分で readdir() を呼んで、 得られたファイル名に grep() した方が速い場合もあります。
'Now is the time for all' . "\n" . 'good men to come to.'と書いても、内部的に 1 つの文字列になります。
foreach $file (@filenames) { if (-s $file > 5 + 100 * 2**16) { ... } }と書くとコンパイラは、式が表わす数値をあらかじめ計算しますの で、インタプリタで計算する必要がなくなっています。
use integer;と書けば、その場所から現在の BLOCK の終わりまでは、整数演算 を行なってよいと、コンパイラに指示することができます。
no integer;と書けば、その BLOCK の終わりまでは、指示を取り消すことにな ります。