演算子の優先順位
|
[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 の終わりまでは、指示を取り消すことにな ります。