PERLOP(1) USER COMMANDS PERLOP(1)
NAME
perlop - Perl の演算子と優先順位
SYNOPSIS
Perl の演算子には、以下のような結合性と優先順位 (高い優先順
位から低いものへ並べている) があります。 C から持ってきた演
算子の優先順位は、C での優先順位が多少おかしくても、そのまま
にしてあることに注意してください。 (これによって、C を使っ
ている方が Perl に移りやすくなっています。)
左結合 項 リスト演算子 (左方向に対して)
左結合 ->
非結合 ++ --
右結合 **
右結合 ! ~ \ 単項の+ 単項の-
左結合 =~ !~
左結合 * / % x
左結合 + - .
左結合 << >>
非結合 名前付き単項演算子
非結合 < > <= >= lt gt le ge
非結合 == != <=> eq ne cmp
左結合 &
左結合 | ^
左結合 &&
左結合 ||
非結合 ..
右結合 ?:
右結合 = += -= *= などの代入演算子
左結合 , =>
非結合 リスト演算子 (右方向に対して)
左結合 not
左結合 and
左結合 or xor
以下の節では、これらの演算子を優先順位に従って紹介します。
DESCRIPTIONS
項とリスト演算子 (左方向)
「項」は Perl でもっとも優先順位が高いものです。 これには、
変数、クォートとクォート的な演算子、括弧で括った任意の式、引
数を括弧で括った任意の関数が含まれます。 実際には、この意味
では本当の関数はなく、リスト演算子と関数のように働く単項演算
子が、引数を括弧で括るためそのように見えます。 これらはすべ
て perlfunc manpage に記述しています。
もし、リスト演算子 (print() など) や単項演算子 (chdir() など)
の名前の後に開き括弧が続く場合には、その演算子と括弧内の引数
は、通常の関数呼び出しのように、もっとも高い優先順位で処理さ
れます。
Perl manpages Last change: Release 5.0 Patchlevel 00 1
PERLOP(1) USER COMMANDS PERLOP(1)
括弧が無い場合には、print、sort、chmod のようなリスト演算子
の優先順位は、演算子の左側をからすると非常に高く、右側からす
ると非常に低く見えます。たとえば、
@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";
の動作を一目見ただけで判断するのは、難しいでしょう。 詳しく
は、「名前付き単項演算子」の節を参照してください。
この他に「項」として解析されるものには、do {} や eval {} の
構成、サブルーティンやメソッドの呼び出し、無名のコンストラク
タ [] と {} があります。
後の方の「クォートとクォートのような演算子」の節や「I/O 演算
子」の節も参照してください。
アロー演算子
C や C++ と同じように "->" は中置の被参照演算子です。 右側
が [...] か {...} の形の添字であれば、左側は配列かハッシュへ
のハードリファレンスかシンボリックリファレンス (あるいは、左
辺値 (代入可能) であればハードリファレンスを保持できる場所)
でなければなりません。 perlref manpage を参照してください。
そうでなければ、右側はメソッド名かメソッド名を持った単純スカ
ラ変数で、左側はオブジェクト (bless されたリファレンス) かク
ラス名でなければなりません。 perlobj manpage を参照してくだ
さい。
Perl manpages Last change: Release 5.0 Patchlevel 00 2
PERLOP(1) USER COMMANDS PERLOP(1)
インクリメントとデクリメント
"++" と "--" は、C の場合と同じように動作します。 つまり、
変数の前に置かれれば、値を返す前に変数をインクリメントまたは
デクリメントし、後に置かれれば、値を返した後で変数をインクリ
メントまたはデクリメントします。
インクリメント演算子には、ちょっと風変わりな機能が組み込まれ
ています。 数値が入った変数や、数値の文脈で使われてきた変数
をインクリメントする場合には、通常のインクリメントとして動作
します。 しかし、その変数が設定されてからずっと文字列の文脈
でしか使われていなくて、空でない /^[a-zA-Z]*[0-9]*$/ にマッ
チする値を持っているときには、個々の文字の範囲を保ちながら桁
あげを行なって、文字列としてインクリメントが行なわれます (マ
ジカルインクリメントと呼ばれます):
print ++($foo = '99'); # '100' と印字
print ++($foo = 'a0'); # 'a1' と印字
print ++($foo = 'Az'); # 'Ba' と印字
print ++($foo = 'zz'); # 'aaa' と印字
デクリメント演算子には、マジカルなものはありません。
指数演算子
二項演算子の "**" は指数演算子です。 この演算子は、単項のマ
イナスよりも結合が強い演算子で、-2**4 は (-2)**4 ではなく、
-(2**4) と解釈されます。
単項演算子
単項演算子の "!" は論理否定を行ないます。 つまり not という
ことです。 この演算子の優先順位を低くしたものとして、"not"
が用意されています。
単項演算子の "-" は被演算子が数値であれば、算術否定を行ない
ます。 被演算子が識別子ならば、マイナス記号にその識別子をつ
なげた文字列が返されます。 これ以外で被演算子の最初の文字が
プラスかマイナスのときには、その記号を逆のものに置き換えた文
字列を返します。 この規則の結果、-bareword が "-bareword"
に等価となります。
単項演算子の "~" はビットごとの否定を行ないます。 つまり、
1 の補数を返します。
単項演算子の "+" は、たとえ文字列に対して用いられた場合にも、
何もしません。 関数名に続けて括弧付きの式を書く場合に、関数
の引数リストと解釈されないようにするために用いることができま
す。 (下記「名前付き単項演算子」の節の例を参照してください。)
Perl manpages Last change: Release 5.0 Patchlevel 00 3
PERLOP(1) USER COMMANDS PERLOP(1)
単項演算子の "\" はその後に続くものへのリファレンスを生成し
ます。 perlref manpage を参照してください。 この用法も文字
列中のバックスラッシュも、後に続くものが解釈されるのを防ぐこ
とになりますが、動作を混同しないでください。
拘束演算子
二項演算子の "=~" は、式をパターンマッチに拘束します。 デフ
ォルトで $_ の文字列を検索したり、変更したりする演算がありま
す。 この演算子は、そのような演算を他の文字列に対して行なわ
せるようにするものです。 右引数は、検索パターン、置換、変換
の何れかです。 左引数は、デフォルトの $_ の代わりに検索、置
換、変換の対象となる対象となります。 返却値は演算の結果が成
功したか否かです。 (右引数が検索パターン、置換、変換ではな
く、式であれば、それは実行時に決まる検索パターンと解釈されま
す。 これは /o を使わない限り、明示的な検索に比べて効率が落
ちます。 式が評価されるたびにパターンをコンパイルする必要が
あるからです。)
二項演算子の "!~" は、返される値が論理否定されることを除いて
"=~" と同じです。
乗法演算子
二項演算子の "*" は 2 つの数値の積を返します。
二項演算子の "/" は 2 つの数値の商を返します。
二項演算子の "%" は 2 つの数値の剰余を返します。
二項演算子の "x" は繰り返し演算子です。 スカラコンテキスト
では、左被演算子を右被演算子に示す数だけ繰り返したもので構成
される文字列を返します。 リストコンテキストでは、左被演算子
が括弧で括られたリストであれば、リストを繰り返します。
print '-' x 80; # 1 列のダッシュを印字
print "\t" x ($tab/8), ' ' x ($tab%8); # タブに畳み込み
@ones = (1) x 80; # 80 個の 1 を含むリスト
@ones = (5) x @ones; # すべての要素を 5 にする
加法演算子
二項演算子の "+" は 2 つの数値の和を返します。
二項演算子の "-" は 2 つの数値の差を返します。
二項演算子の "." は 2 つの文字列を連結します。
Perl manpages Last change: Release 5.0 Patchlevel 00 4
PERLOP(1) USER COMMANDS PERLOP(1)
シフト演算子
二項演算子の "<<" は左引数の値を、右引数で示すビット数だけ、
左にシフトした値を返します。 引数は整数でなければなりません。
二項演算子の ">>" は左引数の値を、右引数で示すビット数だけ、
右にシフトした値を返します。 引数は整数でなければなりません。
名前付き単項演算子
さまざまな名前付き単項演算子が、引数を 1 つ持ち、括弧が省略
可能な、関数として扱われます。 これには -f や -M のようなフ
ァイルテスト演算子も含まれます。 perlfunc manpage を参照し
てください。
リスト演算子 (print() など) や単項演算子 (chdir() など) は、
すべて次のトークンとして開き括弧が続くと、その演算子と括弧内
の引数は、通常の関数呼び出しのようにもっとも高い優先順位とし
て扱われます。 たとえば、|| は chdir より優先順位が低いので、
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)
となります。 「リスト演算子」の節を参照してください。
比較演算子
二項演算子の "<" は左引数が数値的に右引数よりも小さければ、
真を返します。
二項演算子の ">" は左引数が数値的に右引数よりも大きければ、
真を返します。
二項演算子の "<=" は左引数が数値的に右引数よりも小さいか等し
ければ、真を返します。
Perl manpages Last change: Release 5.0 Patchlevel 00 5
PERLOP(1) USER COMMANDS PERLOP(1)
二項演算子の ">=" は左引数が数値的に右引数よりも大きいか等し
ければ、真を返します。
二項演算子の "lt" は左引数が文字列的に右引数よりも小さければ、
真を返します。
二項演算子の "gt" は左引数が文字列的に右引数よりも大きければ、
真を返します。
二項演算子の "le" は左引数が文字列的に右引数よりも小さいか等
しければ、真を返します。
二項演算子の "ge" は左引数が文字列的に右引数よりも大きいか等
しければ、真を返します。
等価演算子
二項演算子の "==" は左引数が数値的に右引数と等しければ、真を
返します。
二項演算子の "!=" は左引数が数値的に右引数と等しくなければ、
真を返します。
二項演算子の "<=>" は左引数が数値的に右引数より小さいか、等
しいか、大きいかに従って、-1, 0, 1 を返します。
二項演算子の "eq" は左引数が文字列的に右引数と等しければ、真
を返します。
二項演算子の "ne" は左引数が文字列的に右引数と等しくなければ、
真を返します。
二項演算子の "cmp" は左引数が文字列的に右引数より小さいか、
等しいか、大きいかに従って、-1, 0, 1 を返します。
ビットごとの AND
二項演算子の "&" は、両被演算子のビットごとに論理積をとって、
その結果を返します。
ビットごとの OR と XOR
二項演算子の "|" は、両被演算子のビットごとに論理和をとって、
その結果を返します。
二項演算子の "^" は、両被演算子のビットごとに排他論理和をと
って、その結果を返します。
Perl manpages Last change: Release 5.0 Patchlevel 00 6
PERLOP(1) USER COMMANDS PERLOP(1)
C スタイルの論理積
二項演算子の "&&" は、短絡の論理積演算を行ないます。 つまり、
左被演算子が偽であれば、右被演算子は評価さえ行なわれないとい
うことです。 評価される場合には、スカラかリストかというコン
テキストは、右被演算子にも及びます。
C スタイルの論理和
二項演算子の "||" は、短絡の論理和演算を行ないます。 つまり、
左被演算子が真であれば、右被演算子は評価さえ行なわれないとい
うことです。 評価される場合には、スカラかリストかというコン
テキストは、右被演算子にも及びます。
|| 演算子と && 演算子は、単に 0 や 1 を返すのではなく、最後
に評価された値を返すという点において、C と違っています。 こ
れにより、かなり一般的に使えるホームディレクトリ ("0" でない
として) を探す方法は:
$home = $ENV{'HOME'} || $ENV{'LOGDIR'} ||
(getpwuid($<))[7] || die "You're homeless!\n";
のようにすることができます。
Perl では、多少読みやすい && と || の同義語として、"and" 演
算子と "or" 演算子が用意されています (下記参照)。 短絡の動
作は全く同じです。 しかし、"and" と "or" の優先順位はかなり
低くしてあるので、引数に括弧を使っていないリスト演算子のあと
に続けて使う場合にも、安心して使うことができます:
unlink "alpha", "beta", "gamma"
or gripe(), next LINE;
C スタイルの演算子では:
unlink("alpha", "beta", "gamma")
|| (gripe(), next LINE);
のように書く必要があります。
範囲演算子
二項演算子の ".." は範囲演算子で、使われるコンテキストによっ
て異なる動作をする 2 つの演算子を合わせたものです。 リスト
コンテキストでは、左の値から右の値まで (1 づつ) 数えあげた値
からなる配列を返します。 これは、for (1..10) のようなループ
を書くときや、配列のスライス演算を行なうときに便利です。 現
状のインプリメントでは、テンポラリの配列が作られるので:
Perl manpages Last change: Release 5.0 Patchlevel 00 7
PERLOP(1) USER COMMANDS PERLOP(1)
for (1 .. 1_000_000) {
# プログラム
}
のようなことを書くと、メモリを使い果たして、悲惨な結果になり
かねませんので注意してください。
スカラコンテキストで使われたときには、".." はブール値を返し
ます。 この演算子は、フリップフロップのように 2 値安定で、
sed や awk や多くのエディタでの行範囲 (コンマ) 演算子をエミ
ュレートするものとなります。 各々の ".." 演算子がそれぞれに
独立して自分のブール状態を管理します。 はじめは、左被演算子
が偽である間、演算全体も偽となっています。 範囲演算子は、い
ったん左被演算子が真になると、右被演算子が真である間、真を返
すようになります。 右被演算子が偽になると、演算子も偽を返す
ようになります。 (次に範囲演算子が評価されるまでは、偽とは
なりません。 (awk でのように) 真となった、その評価の中で右
被演算子をテストし、偽とすることができますが、1 度は真を返す
ことになります。 (sed でのように) 次に評価されるまで、右被
演算子をテストしたくなければ、2 個のドットの代わりに 3 つの
ドット ("...") を使ってください。 右被演算子は、演算子の状
態が「偽」である間は評価されることがなく、左被演算子は、演算
子の状態が「真」である間は評価されることがありません。 優先
順位は、|| と && の少し下です。 偽としては空文字列が返され、
真としては (1 から始まる) 順に並んだ数値が返されます。 この
通し番号は、新たに範囲が始まるごとにリセットされます。 範囲
の最後の数字には、文字列 "E0" がお尻につけられます。 これは、
数値としては何の影響もありませんが、範囲の終わりで何か特別な
ことをしたい場合に、目印として使うことができます。 範囲の始
まりで何かしたい場合には、通し番号が 1 よりも大きくなるのを
待っていればよいでしょう。 スカラの ".." の被演算子が数値リ
テラルであるときは、その被演算子は暗黙に、変数 $. (現行番号)
と比較されることになります。 例:
スカラ演算子として:
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');
Perl manpages Last change: Release 5.0 Patchlevel 00 8
PERLOP(1) USER COMMANDS PERLOP(1)
と書けますし、
$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];
と書けば、16 進の数字が得られますし、
@z2 = ('01' .. '31'); print $z2[$mday];
とすれば、0 付きの日付が得られます。 マジカルインクリメント
によって得られる値の中に指定した最終値にちょうど一致するもの
が見つからないような場合には、マジカルインクリメントによって
得られる次の値の文字列長が、最終値として指定した値のものより
長くなるまでインクリメントが続けられます。
条件演算子
三項演算子の "?:" は、C の場合と同じ条件演算子です。 これは、
if-then-else のように働きます。 "?" の前の引数が真であれば、
":" の前の引数が返されますが、真でなければ、":" の後の引数が
返されます。 スカラコンテキストかリストコンテキストかという
状況は、選択された 2 番目もしくは 3 番目の引数にまで伝わりま
す。 2 番目と 3 番目の引数双方が左辺値 (代入可能ということ)
であれば、この演算子に代入を行なうこともできます:
($a_or_b ? $a : $b) = $c;
このことがプログラムの読みやすさにつながるかどうかは、別問題
なので注意してください。
代入演算子
"=" は通常の代入演算子です。
代入演算子は C の場合と同様の働きをします。 つまり、
$a += 2;
は、
$a = $a + 2;
と等価ですが、tie() のようなもので起こる左辺値の被参照による
副作用が 2 回起こることはありません。 他の代入演算も同様に
働きます。 以下のものが認識されます:
**= += *= &= <<= &&=
-= /= |= >>= ||=
.= %= ^=
x=
Perl manpages Last change: Release 5.0 Patchlevel 00 9
PERLOP(1) USER COMMANDS PERLOP(1)
グループ分けしてありますが、これらはいずれも代入演算子として
同じ優先順位となっています。
C と違って、代入演算子は有効な左辺値を作り出します。 代入を
修正することは、代入を行なってから、その代入された変数を修正
するのと同じことになります。 これは:
($tmp = $global) =~ tr [A-Z] [a-z];
のように何かのコピーを変更したいときに便利です。 同じように、
($a += 2) *= 3;
は、
$a += 2;
$a *= 3;
と等価となります。
二項演算子の "," はコンマ演算子です。 スカラコンテキストで
は、その左引数を評価し、その値を捨てて、それから右引数を評価
し、その値を返します。 これはちょうど、C のコンマ演算子と同
じです。
リストコンテキストでは、これは単にリスト引数の区切り文字で、
双方の引数をそのリストに挿入する働きがあります。
リスト演算子 (右方向)
リスト演算子の右側のものにとって、リスト演算子はとても低い優
先順位になります。 これによってコンマで区切った式をリスト演
算子の引数として、置くことができます。 これよりも優先順位が
低いものは、論理演算子の "and", "or", "not" のみで、余分な括
弧を付けないリスト演算子の呼び出しを評価するために使うことが
できます:
open HANDLE, "filename"
or die "Can't open: $!\n";
「リスト演算子 (左方向)」の節の記述も参照してください。
論理否定
単項演算子の "not" は右側に来る式の否定を返します。 これは、
優先順位がずっと低いことを除いては "!" と等価です。
Perl manpages Last change: Release 5.0 Patchlevel 00 10
PERLOP(1) USER COMMANDS PERLOP(1)
論理積
二項演算子の "and" は両側の式の論理積を返します。 これは、
優先順位がずっと低いことを除けば && と等価です。 つまり、こ
れも短絡演算を行ない、右側の式は左側の式が「真」であった場合
にのみ評価されます。
論理和と排他論理和
二項演算子の "or" は両側の式の論理和を返します。 これは、優
先順位がずっと低いことを除いて || と等価です。 つまり、これ
も短絡演算を行ない、右側の式は左側の式が「偽」であった場合に
のみ評価されます。
二項演算子の "xor" は両側の式の排他論理和を返します。 これ
はもちろん、短絡ではありません。
Perl にない C の演算子
C にあって Perl に無いものは以下の通りです:
単項 & アドレス演算子。 ("\" 演算子がリファレンスのために
用いられます。)
単項 * 被アドレス参照演算子。 (Perl の被参照プリフィクス演
算子が型づけを行なう: $, @, %, &。)
(型) 型のキャスト演算子。
クォートとクォートのような演算子
クォートはリテラル値であると考えるのが普通ですが、Perl にお
いて、クォートは演算子として働き、さまざまな展開やパターンマ
ッチの機能を持っています。 そのような動作をさせるのに、Perl
は慣習的にクォート文字を使っていますが、どの種類のクォートも、
自分でクォート文字を選べるようになっています。 以下の表では、
{} がその選んだ区切文字のペアを示しています。 選んだ区切文
字が括弧の類でない場合には、前後の文字として同一のものを使い
ますが、4 つの括弧 ((), <>, [], {}) の場合にはネストできます。
通常記法 汎用記法 意味 展開
===========================================
'' q{} リテラル 不可
"" qq{} リテラル 可
`` qx{} コマンド 可
qw{} 単語リスト 不可
// m{} パターンマッチ 可
s{}{} 置換 可
tr{}{} 変換 不可
Perl manpages Last change: Release 5.0 Patchlevel 00 11
PERLOP(1) USER COMMANDS PERLOP(1)
展開が行なわれる構文では、"$" や "@" で始まる変数が、以下の
シーケンスと同時に展開されます:
\t タブ
\n 改行
\r 復帰
\f 改ページ
\v 垂直タブ (それが何であっても)
(訳注: これは使えないように見える)
\b バックスペース
\a アラーム (ベル)
\e エスケープ
\033 8 進数で表した文字
\x1b 16 進数で表した文字
\c[ コントロール文字
\l 次の文字を小文字にする
\u 次の文字を大文字にする
\L \E まで小文字にする
\U \E まで大文字にする
\E 変更の終わり
\Q \E まで正規表現のメタ文字をクォートする
パターンはさらに、正規表現として展開が行なわれます。 これは、
変数が展開された後の 2 回目のパスで行なわれるので、変数に正
規表現を含めておき、パターンの中へ展開することができます。
もし、そうしたくないのであれば、\Q を使うと変数の内容を文字
どおりに展開することができます。
上記のものを除けば、複数の段階を踏んで展開が行なわれることは
ありません。 特に、シェルのプログラマの期待とは裏腹に、バッ
ククォートはダブルクォートの中では展開されませんし、シングル
クォートがダブルクォートの中で使われても、変数の展開を妨げる
ことはありません。
?PATTERN?
これは、reset() 演算子を呼び出すごとに 1 度だけしか
マッチしないことを除いては /pattern/ による検索と全
く同じです。 たとえば、ファイルの集まりの中で個々の
ファイルについて、あるものを探すとき、最初の 1 つだ
けの存在がわかれば良いのであれば、この機能を使って最
適化をはかることができます。 現在のパッケージにロー
カルとなっている ?PATTERN? のパターンだけが reset さ
れます。
この方法は、あまりお勧めしません。 Perl の将来のバ
ージョンでは削除されるかもしれません。
m/PATTERN/gimosx
/PATTERN/gimosx
パターンマッチで文字列検索を行ない、スカラコンテキス
Perl manpages Last change: Release 5.0 Patchlevel 00 12
PERLOP(1) USER COMMANDS PERLOP(1)
トでは真 (1) または偽 ('') を返す。 =~ 演算子か !~
演算子で検索対象の文字列を示さなかったときには、$_
の文字列が検索対象となります。 (=~ で指定される文字
列は、左辺値である必要はありません。 式を評価した結
果でもかまいませんが、=~ の優先順位がいくぶん高いこ
とに注意してください。) perlre manpage を参照してく
ださい。
オプションには、
g グローバルにマッチ、つまり、すべてを探し出す
i 大文字、小文字を区別しない
m 文字列を複数行として扱う
o パターンのコンパイルを 1 度だけにする
s 文字列を単一行として扱う
x 拡張正規表現を使用する
があります。
区切文字が "/" のときには、最初の m は付けても付けな
くてもかまいません。 m を付けるときには、英数字でも
空白でもない、任意の任意の文字のペアを、区切文字とし
て使うことができます。 これは "/" を含む UNIX のパ
ス名にパターンパッチを行なうときに便利でしょう。 \/
といった LTS (楊枝偏執症候群) を避けるためにも。
PATTERN には、変数が含まれていてもよく、パターンが評
価されるごとに、変数は展開され (パターンが再コンパイ
ルされ) ます。 (2 つの変数 $) と $| は文字列の終わ
りを調べるパターンであると解釈されるので、展開されま
せん。) パターンがコンパイルされるのを 1 度だけにし
たい場合には、終わりの区切文字の後に /o 修飾子を付け
ます。 これにより、実行時に再コンパイルが頻繁に起こ
ることが避けられ、展開する値がスクリプトの実行中に変
化しない場合に有効なものとなります。 しかし、/o を
付けることは、パターンの中の変数を変更しないことを約
束するものです。 変更したとしても、Perl がそれに気
付くことはありません。
PATTERN を評価した結果が空文字列となった場合には、最
後に実行され (コンパイルに成功し) た正規表現が、代わ
りに使われます。
パターンマッチが、リスト値が要求されるコンテキストで
使われると、パターンの中の括弧で括られた部分列にマッ
チしたもので構成されるリストを返します。 これは、
($1, $2, $3, ...) ということです。 (この場合、$1 な
ども設定されます。 この点で Perl 4 の動作と違ってい
ます。) マッチが失敗した場合には、空配列が返されま
す。 マッチが成功した場合で、括弧が無い場合には、リ
スト値 (1) が返されます。
Perl manpages Last change: Release 5.0 Patchlevel 00 13
PERLOP(1) USER COMMANDS PERLOP(1)
例:
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 に代入しています。 変数に代
入されれば、すなわちパターンがマッチすれば、if の条
件が真となります。
/g 修飾子は、グローバルなパターンマッチを指定するも
ので、文字列の中で可能な限りたくさんマッチを行ないま
す。 この動作は、コンテキストに依存します。 リスト
コンテキストでは、正規表現内のすべての括弧付けされた
ものにマッチした部分文字列全部のリストが返されます。
括弧がなければ、パターン全体を括弧で括っていたかのよ
うに、すべてのマッチした文字列のリストが返されます。
スカラコンテキストでは、m//g は文字列内で繰り返しを
行ない、マッチするごとに「真」を返し、最終的にマッチ
しなくなったときに「偽」を返します。 (言い換えると、
前回止まった場所を覚えていて、その場所から検索を再開
するということです。 文字列の現在の検索位置は、関数
pos() を使って知ることができます。 perlfunc manpage
を参照してください。) いかなる方法でも、対象の文字
列を変更すると、検索位置は先頭にリセットされます。
例:
# リストコンテキスト
($one,$five,$fifteen) = (`uptime` =~ /(\d+\.\d+)/g);
# スカラコンテキスト
$/ = ""; $* = 1; # Perl 5 では、$* は使わないほうがよい
while ($paragraph = <>) {
while ($paragraph =~ /[a-z]['")]*[.!?]+['")]*\s/g) {
$sentences++;
}
}
print "$sentences\n";
Perl manpages Last change: Release 5.0 Patchlevel 00 14
PERLOP(1) USER COMMANDS PERLOP(1)
q/STRING/
'STRING'
シングルクォートされた、リテラル文字列です。 バック
スラッシュは、後ろに続くものが区切文字か、別のバック
スラッシュである場合を除いて無視されます。 区切文字
やバックスラッシュが続く場合には、その区切文字自身も
しくはバックスラッシュそのものが展開されます。
$foo = q!I said, "You said, 'She said it.'"!;
$bar = q('This is it.');
qq/STRING/
"STRING"
ダブルクォートされた、リテラル文字列です。
$_ .= qq
(*** The previous line contains the naughty word "$1".\n)
if /(tcl|rexx|python)/; # :-)
qx/STRING/
`STRING`
展開され、システムのコマンドとして実行される文字列で
す。 そのコマンドの、標準出力を集めたものが返されま
す。 スカラコンテキストでは、(複数行を含むかもしれ
ない) 1 つの文字列が戻ってきます。 リストコンテキス
トでは、($/ もしくは $INPUT_RECORD_SEPARATOR をどの
ように設定していても) 行のリストを返します。
$today = qx{ date };
詳しくは「I/O 演算子」の節を参照してください。
qw/STRING/
埋め込まれた空白を区切文字として、STRING から抜き出
した単語のリストを返します。 これは、
split(' ', q/STRING/);
と完全に同じになります。
よく行なわれる例としては:
use POSIX qw( setlocale localeconv )
@EXPORT = qw( foo bar baz );
というものがあります。
Perl manpages Last change: Release 5.0 Patchlevel 00 15
PERLOP(1) USER COMMANDS PERLOP(1)
s/PATTERN/REPLACEMENT/egimosx
文字列中でパターンを検索し、もし見つかれば、置換テキ
ストで置き換え、置換した数を返します。 見つからなけ
れば、偽 (0) を返します。
=~ 演算子や !~ 演算子によって文字列が指定されていな
ければ、変数 $_ が検索され、修正されます。 (=~ で指
定される文字列は、スカラ変数、配列要素、ハッシュ要素、
あるいは、これらへの代入式といった左辺値でなければな
りません。)
あとで述べますが、区切り文字はスラッシュとは限りませ
ん。 シングルクォートを区切り文字として使った場合に
は、PATTERN にも REPLACEMENT にも変数の展開を行ない
ません。 それ以外の場合、文字列の最後を表わすものに
は見えない $ が PATTERN に含まれると、実行時に変数が
パターン内に展開されます。 最初に変数が展開されると
きにだけパターンのコンパイルを行ないたいときには、/o
オプションを使ってください。 パターンの評価結果が空
文字列になった場合には、最後に実行され (コンパイルに
成功し) た正規表現が代わりに使われます。 これについ
てさらに詳しくは、perlre manpage を参照してください。
オプションには、
e 式の右側の評価を行なう
g グローバルな置換、つまり見つかったものすべて
i 大文字、小文字を区別しないで検索
m 文字列を複数行として扱う
o パターンのコンパイルを 1 度だけにする
s 文字列を単一行として扱う
x 拡張正規表現を使用する
があります。
英数字、空白ではない任意の区切り文字で、スラッシュを
置き換えることができます。 先に述べたように、シング
ルクォートを使うと置換文字列での展開はされません (/e
修飾子を使えば可能です)。 バッククォートを用いると、
置換文字列をコマンドとして実行して、その出力が実際の
置換文字列に使われます。 PATTERN を括弧類で括った場
合には、REPLACEMENT 用にもう一組の区切り文字を用意し
ます。 これは、括弧類であっても、なくてもかまいませ
ん。 例: s(foo)(bar) や s<foo>/bar/。 /e は置換文
字列を完全な Perl の式として解釈し、その場所で直ちに
eval() します。 しかし、これはコンパイル時に構文チ
ェックされます。
Perl manpages Last change: Release 5.0 Patchlevel 00 16
PERLOP(1) USER COMMANDS PERLOP(1)
例:
s/\bgreen\b/mauve/g; # wintergreen は変更しない
$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 語の入れ替え
最後の例で \ の代わりに $ を使っているのに注意してく
ださい。 sed と違って、\<数字> の形式はパターンの方
でのみ使用できます。 その他の場所では、$<数字> を使
います。
ときには、/g を付けるだけでは、すべてを変更すること
ができないことがあります。 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;
Perl manpages Last change: Release 5.0 Patchlevel 00 17
PERLOP(1) USER COMMANDS PERLOP(1)
tr/SEARCHLIST/REPLACEMENTLIST/cds
y/SEARCHLIST/REPLACEMENTLIST/cds
検索リスト (SEARCHLIST) に含まれる文字を、対応する置
換リスト (REPLACEMENTLIST) の文字に変換します。 置
換または削除が行なわれた、文字数を返します。 =~ 演
算子や =! 演算子で文字列が指定されていなければ、$_
の文字列が変換されます。 (=~ で指定される文字列は、
スカラ変数、配列要素、ハッシュ要素、あるいは、これら
への代入式といった左辺値でなければなりません。) sed
の信仰者のために y が tr の同義語として提供されてい
ます。 SEARCHLIST を括弧類で括った場合には、
REPLACEMENTLIST 用に、もう一組の区切り文字を用意しま
す。 これは、括弧類であっても、なくてもかまいません。
例: tr[A-Z][a-z] や tr(+-*/)/ABCD/。
オプションには、
c SEARCHLIST を補集合にする
d 見つかったが置換されなかった文字を削除する
s 置換された文字が重なったときに圧縮する
があります。
/c 修飾子が指定されると、SEARCHLIST には補集合が指定
されたものと解釈されます。 /d 修飾子が指定されると、
SEARCHLIST に指定されて、REPLACEMENTLIST に対応する
ものがない文字が削除されます。 (これは、SEARCHLIST
で見つかったものを削除する、ただそれだけの、ある種の
tr プログラムの動作よりと比べれば、いく分柔軟なもの
になっています。) /s 修飾子が指定されると、同じ文字
に置き換えられた文字の並びを、その文字 1 文字だけに
圧縮します。
/d 修飾子が使われると、REPLACEMENTLIST は、常に指定
された通りに解釈されます。 /d が指定されない場合で、
REPLACEMENTLIST が SEARCHLIST よりも短いと、同じ長さ
になるまで、REPLACEMENTLIST の最後の文字が繰り返され
ているものとして扱われます。 REPLACEMENTLIST が空文
字列でのときには、SEARCHLIST と同じになります。 後
者は、ある文字クラスに含まれる文字数を数えるときや、
ある文字クラスの文字の並びを圧縮するようなときに便利
です。
例:
$ARGV[1] =~ tr/A-Z/a-z/; # 小文字に統一
$cnt = tr/*/*/; # $_ 内の * を数える
$cnt = $sky =~ tr/*/*/; # $sky 内の * を数える
Perl manpages Last change: Release 5.0 Patchlevel 00 18
PERLOP(1) USER COMMANDS PERLOP(1)
$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() を使わな
ければならないということです:
eval "tr/$oldlist/$newlist/";
die $@ if $@;
eval "tr/$oldlist/$newlist/, 1" or die $@;
I/O 演算子
知っておいた方がよい I/O 演算子もいくつかあります。 バック
クォートで括られた文字列は、まず、ダブルクォート文字列のよう
に、変数の展開が行なわれます。 その後、シェルでの場合と同じ
ように、コマンドとして解釈され、そのコマンドの出力がこの擬似
リテラルの値となります。 スカラコンテキストでは、出力すべて
を含む一個の文字列が返されます。 リストコンテキストでは、出
力の 1 行 1 行が個々の要素となるリストが返されます。 ($/ を
設定すれば、行の終わりを示す文字を変えることができます。)
コマンドは、この擬似リテラルが評価されるごとに実行されます。
コマンドのステータス値は $? に返されます ($? の解釈について
は、perlvar manpage を参照してください)。 csh での場合とは
違って、結果のデータに対する変換は行なわれず、改行は改行のま
まです。 どのシェルとも違って、シングルクォートがコマンド中
の変数名を解釈させないようにすることはありません。 シェルに
$ を渡すには、バックスラッシュでエスケープしなければなりませ
ん。 バッククォートの一般形は、qx// です。
山括弧の中のファイルハンドルを評価すると、そのファイルから、
次の行を読み込むことになります (改行も含まれるので、未定義値
が返される EOF に達するまでは、偽と評価される値が返ることは
ありません)。 通常は、その値を変数に代入しなければなりませ
んが、自動的に代入される場合が 1 つだけあります。 この入力
シンボルが、while ループの条件式中に単独で現れた場合だけは、
その値が自動的に変数 $_ に代入されます。 (これは、奇妙に思
えるかもしれませんが、ほとんどすべての Perl スクリプトでこれ
が必要になることでしょう。) いずれにせよ、以下のものは、お
互いに同値なものです:
Perl manpages Last change: Release 5.0 Patchlevel 00 19
PERLOP(1) USER COMMANDS PERLOP(1)
while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while $_ = <STDIN>;
print while <STDIN>;
STDIN、STDOUT、STDERR というファイルハンドルは、あらかじめ定
義されています。 (stdin、stdout、stderr というファイルハン
ドルも、ローカルな名前でこれらのグローバルな名前が見えなくな
っているパッケージを除けば、使用することができます。) その
他のファイルハンドルは、open() 関数で作ることができます。
<FILEHANDLE> がリストを必要とするコンテキストで用いられると、
1 要素に 1 行の入力行すべてからなるリストが返されます。 こ
れを使うと簡単に巨大なデータが作られてしまいますので、注意を
要します。
ヌルファイルハンドル <> は特別で、sed や awk の動作をエミュ
レートするために使われます。 <> からの入力は、標準入力から
か、コマンドライン上に並べられた個々のファイルから行なわれま
す。 動作の概要は、以下のようになります。 最初に <> が評価
されると、配列 @ARGV が調べられ、空であれば、$ARGV[0] に "-"
を設定します。 これは、open されるとき標準入力となります。
その後、配列 @ARGV がファイル名のリストとして処理されます。
while (<>) {
... # 行ごとの処理
}
というループは、
unshift(@ARGV, '-') if $#ARGV < $[;
while ($ARGV = shift) {
open(ARGV, $ARGV);
while (<ARGV>) {
... # 行ごとの処理
}
}
のような Perl の擬似コードと等価です。 わずらわしく書かなく
ても、動作します。 実際に @ARGV を shift しますし、その時点
のファイル名を変数 $ARGV に入れています。 また、内部的にフ
ァイルハンドル ARGV を使っていて、<> は不思議な <ARGV> の同
義語となっています。 (上記の擬似コードは、<ARGV> を通常のも
のとして扱っているので、うまく動作しません。)
最終的に、@ARGV に扱いたいと思っているファイル名が含まれるの
であれば、最初に <> を評価する前に @ARGV を変更することも可
能です。 行番号 ($.) は、入力ファイルがあたかも 1 つの大き
なファイルであるかのように、続けてカウントされます。 (個々
のファイルごとにリセットする方法は、perlfunc manpage の eof()
Perl manpages Last change: Release 5.0 Patchlevel 00 20
PERLOP(1) USER COMMANDS PERLOP(1)
の例を参照してください。)
最初から @ARGV に自分でファイルのリストを設定してもかまいま
せん。 スクリプトにスイッチを渡したいのであれば、Getopts モ
ジュールを使うこともできますし、実際の処理の前に
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, $_;
}
と等価です。 実際、現在はそのようにインプリメントされていま
す。 (つまり、マシン上に csh(1) がないと、スペースを含むフ
Perl manpages Last change: Release 5.0 Patchlevel 00 21
PERLOP(1) USER COMMANDS PERLOP(1)
ァイル名は、うまく扱えないということです。) もちろん、もっ
と簡単に
chmod 0644, <*.c>;
と書けます。
グロブはシェルを呼び出しますから、自分で readdir() を呼んで、
得られたファイル名に grep() した方が速い場合もあります。 さ
らに、現在のインプリメントがシェルを使うために、(/bin/csh と
して tcsh(1L) をインストールしていない限り) glob() ルーティ
ンで "Arg list too long" エラーが発生する場合があります。
定数の畳み込み
C と同じように Perl でも、演算子に対するすべての引数がスタテ
ィックで、副作用がないと判断できれば、コンパイル時に式の評価
を行なってしまいます。 特に、変数置換の無いリテラルどうしの
文字列連結はコンパイル時に行なわれます。 バックスラッシュの
解釈もコンパイル時に行なわれます。
'Now is the time for all' . "\n" .
'good men to come to.'
と書いても、内部的に 1 つの文字列になります。 同様に
foreach $file (@filenames) {
if (-s $file > 5 + 100 * 2**16) { ... }
}
と書くとコンパイラは、式が表わす数値をあらかじめ計算しますの
で、インタプリタで計算する必要がなくなっています。
整数演算
デフォルトでは、Perl は演算を浮動小数で行なわなければならな
いものとしていますが、
use integer;
と書けば、その場所から現在の BLOCK の終わりまでは、整数演算
を行なってよいと、コンパイラに指示することができます。 内部
の BLOCK で、
no integer;
と書けば、その BLOCK の終わりまでは、指示を取り消すことにな
ります。
Perl manpages Last change: Release 5.0 Patchlevel 00 22