演算子とは、1つ以上のオペランドを伴って式を構成する構文要素です。 オペランドの数によって、単項演算子・二項演算子・三項演算子に分類されます。 同じ記号を使っても、単項演算子だったり二項演算子であったりする演算子もあります。 問えば、符号反転-$xと減算$x - $y は、同じ記号 - を使います。 さらに、デクリメント--$x も、同じ記号 - を使います(--で1つのトークンで間に空白などは入れられません)。

また。Perlの演算子は、オペランドの型を演算子の想定する型に強制的に型変換され演算が行われます。

$x + $y # 加算。オペランドが数値でない場合は数値に変換してから加算。
$x . $y # 結合。オペランドが文字列でない場合は文字列に変換してから結合。
$x x $y # 繰返し。左オペランドの文字列とみなし、右オペランドを数値とみなし、その回数だけ繰り返す。
このように演算子がわかれば、オペランドの型もわかります。
フランス語の名詞を憶えるときに性も同時に憶えるように、Perl の演算子を憶えるときにはオペランドの型も同時に憶えましょう。
多くのオペランドはスカラーです。
インクリメント++のように数値も文字列もとり得る例外や、二項演算子の x の様にリストを取る例外もありますが、本則を覚えたあと、各個の例外を理解するのが全体を理解する早道です。

演算子の優先度と結合性

編集

演算子の優先順位と結合性は、Perlでは概ね数学の世界と同じように機能します。

演算子の優先順位は、ある演算子が他の演算子よりも強くグループ化されることを意味します。たとえば、2 + 4 * 5 の場合、乗算の方が優先順位が高いので、2 + 4 が乗算の左側のオペランドとしてグループ化されるよりも、4 * 5 が加算の右側のオペランドとしてグループ化されます。つまり、式は (2 + 4) * 5 ではなく、2 + (4 * 5) と書かれるようなもので、6 * 5 == 30 ではなく、2 + 20 == 22 となります。

演算子の優先度と結合方向[1]
演算子 結合方向
項 リスト演算子(左から)
->
++ -- 無結合
**
! ~ ~. \ +項 -項
=~ !~
* / % x
+ - .
<< >>
名前付き単項演算子 無結合
isa 無結合
< > <= >= lt gt le ge 連鎖[2]
== != eq ne <=> cmp ~~ 連鎖/無結合[2]
& &.
| |. ^ ^.
&&
|| //
.. ... 無結合
?:
= += -= *= などの代入演算子 goto last next redo dump
, =>
リスト演算子 (右から) 無結合
not
and
or xor

代入演算子

編集
左辺の変数に右辺のオブジェクトを束縛します。
my, localstate による変数宣言に伴う = は代入ではなく初期化です。
コード例
#!/usr/bin/perl
use v5.30.0;
use warnings;

my $x = 1;   # $x を 1 で初期化
say "\$x = $x";

$x = "abc";  # $x に "abc" を代入
say "\$x = $x";

my @x = ("xyz", 1, 3.14);  # @x を ("xyz", 1, 3.14) で初期化
say "\@x = @x";
say "\$x = $x";

my $y = 0;
$x = $y = 123;
say "\$x = $x, \$y  = $y";
実行結果
$x = 1
$x = abc
@x = xyz 1 3.14
$x = abc 
$x = 123, $y  = 123
$x の値に注目すると、代入するたびに方が違うオブジェクトに束縛されています。
これは正常な動作で、strict プラグマがあってもwarningsプラグマがあっても、違う型の値の代入もエラーも警告も出ません。
@x に代入した後も、$x の値は変わらないので「名前が同じでも接頭辞($ @ や %)が違う変数は別の変数」であることがわかります。
代入は式で、値は代入された値です。
代入は右結合なので、$x = $y = 123$x = ( $y = 123 ) と解されます。

LEFT OP= 右 の形式の演算子は、LEFT = LEFT OP 右 と等価です。 OP= で1つのトークンです。OP= の間に空白や改行があってはいけません。

$x += $y;     # $x = $x + $y と等価
$x -= $y;     # $x = $x - $y と等価
$x *= $y;     # $x = $x * $y と等価
$x /= $y;     # $x = $x / $y と等価
$x %= $y;     # $x = $x % $y と等価
$x **= $y;    # $x = $x ** $y と等価
use v5.30.0;

my $x;
$x .= "abc";
say $x;

$x .= "XYZ";
say $x;
実行結果
abc 
abcXYZ
文字列を結合して代入します。
変数が未定義、あるいはみ初期化の場合(undefの場合)、undefが "" に自動変換され右辺の値と結合…つまり普通の代入が行なわれます。
use v5.30.0;

my $x  = "abc";
$x x= 4;
say $x;
実行結果
abcabcabcabc
繰返して代入します。

算術演算子

編集
四則演算と剰余および累乗です。
四則演算と剰余および累乗
#!/usr/bin/perl

use strict;
use warnings;

foreach my $x(-7, 0, -7) {
    foreach my $y(-3, 1, 3) {
        foreach my $op(qw(+ - * / % **)) {
            my $expr = "$x $op $y";
            print "$expr -> @{[eval $expr]}:\t"
        }
        print "\n"
    }
}
実行結果
-7 + -3 -> -10:	-7 - -3 -> -4:	-7 * -3 -> 21:	-7 / -3 -> 2.33333333333333:	-7 % -3 -> -1:	-7 ** -3 -> -0.00291545189504373:	
-7 + 1 -> -6:	-7 - 1 -> -8:	-7 * 1 -> -7:	-7 / 1 -> -7:	-7 % 1 -> 0:	-7 ** 1 -> -7:	
-7 + 3 -> -4:	-7 - 3 -> -10:	-7 * 3 -> -21:	-7 / 3 -> -2.33333333333333:	-7 % 3 -> 2:	-7 ** 3 -> -343:	
0 + -3 -> -3:	0 - -3 -> 3:	0 * -3 -> 0:	0 / -3 -> 0:	0 % -3 -> 0:	0 ** -3 -> Inf:	
0 + 1 -> 1:	0 - 1 -> -1:	0 * 1 -> 0:	0 / 1 -> 0:	0 % 1 -> 0:	0 ** 1 -> 0:	
0 + 3 -> 3:	0 - 3 -> -3:	0 * 3 -> 0:	0 / 3 -> 0:	0 % 3 -> 0:	0 ** 3 -> 0:	
-7 + -3 -> -10:	-7 - -3 -> -4:	-7 * -3 -> 21:	-7 / -3 -> 2.33333333333333:	-7 % -3 -> -1:	-7 ** -3 -> -0.00291545189504373:	
-7 + 1 -> -6:	-7 - 1 -> -8:	-7 * 1 -> -7:	-7 / 1 -> -7:	-7 % 1 -> 0:	-7 ** 1 -> -7:	 
-7 + 3 -> -4:	-7 - 3 -> -10:	-7 * 3 -> -21:	-7 / 3 -> -2.33333333333333:	-7 % 3 -> 2:	-7 ** 3 -> -343:
除算は浮動小数点数を返すのに、剰余演算は整数を返すことです。
また、剰余演算は -7 % -3 -> -1 と若干癖があります。

インクリメントとデクリメント

編集
インクリメントは変数の値を1増します。
$x++は、$x += 1および$x = $x + 1と等価な演算を行います。
++ は前置すること(++$x)も後置すること($x++)もできます。
インクリメント
#!/usr/bin/perl

use strict;
use warnings;

my $x = 10;
print "\$x = $x\n";

$x++;
print "\$x = $x\n";

++$x;
print "\$x = $x\n";

print $x++ . "\n";
print "\$x = $x\n";

print ++$x . "\n";
print "\$x = $x\n";

my $q;
$q++;
print "\$q = $q\n";
実行結果
$x = 10
$x = 11
$x = 12
12
$x = 13
14
$x = 14 
$q = 1
前置++$xでも後置$x++でも実行結果は同じです。
式の値は
前置++$x
インクリメント後の値
後置$x++
インクリメント前の値
と異なります。
最後の $q はややトリッキーです。
宣言だけで初期化を行なわないスカラー変数の値は undef です。この変数をインクリメントする場合
undef が数値に変換される undef ⇒ 0、変換された 0 をインクリメント ⇒ 1 という反応経路になります。

 

マジカルインクリメント

編集

Perlでは、演算子が決まるとオペランドの型が確定するのですが、インクリメントは例外で、数値のときは $x++ ⇒ $x += 1 ⇒ $x = $x + 1 ですが、文字列を渡すと一風変わった挙動をします。

print <<EOS;
@{[ ++($foo = "99") ]}
@{[ ++($foo = "a0") ]}
@{[ ++($foo = "Az") ]}
@{[ ++($foo = "zz") ]}
EOS
実行結果
100
a1
Ba 
aaa
この文字烈に対する不思議なインクリメントをマジカルインクリメントと呼びます。
デクリメントに、マジカルデクリメントはありません。
デクリメントは変数の値を1減らします。
$x--は、$x -= 1および$x = $x - 1と等価な演算を行います。
-- は前置すること(--$x)も後置すること($x--)もできます。
デクリメント
#!/usr/bin/perl

use strict;
use warnings;

my $x = 10;
print "\$x = $x\n";

$x--;
print "\$x = $x\n";

--$x;
print "\$x = $x\n";

print $x-- . "\n";
print "\$x = $x\n";

print --$x . "\n";
print "\$x = $x\n";

my $q;
$q--;
print "\$q = $q\n";
実行結果
$x = 10
$x = 9
$x = 8
8
$x = 7
6
$x = 6 
$q = -1
前置--$xでも後置$x--でも実行結果は同じです。
式の値は
前置--$x
デクリメント後の値
後置$x--
デクリメント前の値
と異なります。
最後の $q はややトリッキーです。
宣言だけで初期化を行なわないスカラー変数の値は undef です。この変数をデクリメントする場合
undef が数値に変換される undef ⇒ 0、変換された 0 をデクリメント ⇒ -1 という反応経路になります。

文字列連結演算子

編集

.(ピリオド)は、文字列同士を連結して別の文字列を返す演算子、文字列連結演算子です。

#!/usr/bin/perl
use v5.30.0;
use warnings;

say "ABC" . "XYZ";
say "ABC" . "XYZ" x 3;
say "ABC" x 3 . "XYZ";
実行結果
ABCXYZ
ABCXYZXYZXYZ 
ABCABCABCXYZ
. は、二項演算子です。
次節で説明するx繰返し演算子と併用すると、xの方が. より優先度が高いので、*+の関係のようにx側の部分式が先に評価されます。

繰返し演算子

編集

x は、繰返し演算子です。 Perlにしては珍しく、オペランドによって演算内容と返す型が変わります。

#!/usr/bin/perl
use v5.30.0;
use warnings;

say "ABC" x 2;
say "ABC" x 3.7; # 右辺に浮動小数点数を与えても、整数として評価されます。
#say "ABC" x -5; # XXX: 右辺に負数を与えると ーー> Negative repeat count does nothing
#say 2 x "ABC";  # XXX: 右辺に数値以外を与えると ーー> Argument "ABC" isn't numeric in repeat (x)

my @ary = qw(abc def ghi);
say "@{[ @ary x 9 ]}";           # 右辺が数値の場合、左辺は文字列に型強制され配列は要素数を文字列化されます。
say "@{[ 9 x @ary ]}";           # 数値 x 配列は、配列の要素を数値に置換えた文字列(配列ではありません)を返します。 
say "@{[ qw(1 2 3 4) x @ary ]}"; # 配列左 x 配列右は、配列右の要素を配列左に置換えた配列を返します。
実行結果
ABCABC
ABCABCABC
333333333
999 
1 2 3 4 1 2 3 4 1 2 3 4

クオート演算子

編集

q/STRING/は、文字列リテラルを表します。 変数と式の展開は、行なわれません。 (シングルクオーテーション)で囲まれた文字列リテラルに相当しますが、\(バックスラッシュ)でエスケープする必要はありません。 \の変換規則は、下記の実行結果のように変則的です。

q/STRING/
use v5.30.0;

my $c = 'I\'m fine.';
my $d = q(I'm fine.);
say $c eq $d ? "一致" : "不一致";

say q(1: I\'m fine.);
say q(2: I\\'m fine.);
say q(3: I\\\'m fine.);
say q(4: I\\\\'m fine.);
実行結果
一致
1: I\'m fine.
2: I\'m fine.
3: I\\'m fine. 
4: I\\'m fine.

qq/STRING/は、文字列リテラルを表します。 変数と式の展開が、行なわれます。 "(ダブルクオーテーション)で囲まれた文字列リテラルに相当しますが、をエスケープする必要はありません。 \の変換規則は、下記の実行結果のように変則的です。

qq/STRING/
use v5.30.0;

my $x = "Hello, \"$^V\"!";
my $y = qq(Hello, "$^V"!);
say $x;
say $y;

say qq(1: \");
say qq(2: \\");
say qq(3: \\\");
say qq(4: \\\\");
実行結果
Hello, "v5.30.0"!
Hello, "v5.30.0"!
1: "
2: \"
3: \" 
4: \\"

qw/STRING/は、空白および改行で区切られた文字列を、文字リテラルを要素とするリストを表します。 変数と式の展開は、行なわれません。 対応する他のリテラル表現がありませんが、概ね

qw/STRING/
split(" ", q/STRING/)
に相当しますが、厳密には qw/STRING/は、コンパイル時に実際のリストを生成し、スカラーコンテキストではリストの最後の要素を返します。
qw/STRING/
use v5.30.0;

my $x = qw(a bc def);
my @y = qw(a bc def);
my $z = @y;

say "\$x --> $x";
say "\@y --> @y";
say "\$z --> $z"
実行結果
$x --> def
@y --> a bc def 
$z --> 3

よくある間違えとしては、セパレーターとして ,(カンマ)を使ってしまったり、(複数行のqw/STRING/で)#(井桁)をコメントになると期待してしまうことです。 これは、use warnings;か、use v5.36.0; warnings プラグマを有効にすることで警告を受けます(Perl5.36.0以降は warnings プラグマが標準で有効で、無効にするには no warnings; とします)。

qw/STRING/(警告あり)
use v5.30.0;
use warnings;

my @x = qw(a,bc,def);
my @y = qw@
Hello world!     # world
Hello perl!      # perl
Hello universe!  # universe
@;

say "\@x --> @x";
say "\@y --> @y";
コンパイル結果
Possible attempt to separate words with commas at Main.pl line 4. 
Possible attempt to put comments in qw() list at Main.pl line 9.
実行結果
@x --> a,bc,def 
@y --> Hello world! # world Hello perl! # perl Hello universe! # universe

正規表現リテラルの一般化

$x = qr/^Regexp$/i;

バッククォートリテラルの一般化

$x = qx/uname -a/;   # `uname -a`; と同じ

ヒアドキュメント

編集

行指向のクォートの形式は、シェルのヒアドキュメント構文に基づくものです。 << の後に引用を終了する文字列を指定すると、現在の行から終了文字列までのすべての行が、その項目の値となります。

終了文字列の前に ~ を付けると、「インデント付きHere-docs」を使用することを指定します。

終了文字列は、識別子(単語)か、引用符で囲まれたテキストのどちらかです。 引用符で囲まれていない識別子は二重引用符のように機能します。 <<と識別子の間には、識別子が明示的に引用されていない限り、スペースを入れてはいけません。 終端文字列は,終端行に単独で (引用せず,周囲に空白を入れずに) 表示されなければなりません。

終了文字列が引用されている場合、使用される引用符の種類によって、そのテキストの扱いが決まります。

ダブルクォーテーションマーク "
通常のダブルクォーテーションマークで囲まれた文字列と全く同じ規則でテキストが補間されることを示します。
シングルクォーテーションマーク '
テキストがその内容を補間することなく、文字通りに扱われることを示します。これは、バックスラッシュが特別な意味を持たないことを除けば、一重引用符で囲まれた文字列と同様です。
シェルと同様、<<に続くバックスラッシュ付きの単語は、シングルクォート文字列と同じ意味を持ちます。
バッククォーテーションマーク `
文字列がバッククォーテーションマークで埋込まれている場合と同じように扱われます。すなわち、内容は二重引用符で囲まれているかのように補間され、シェル経由で実行され、その実行結果が返されます。
クォーテーションマークなし
(ダブルクォーテーションマークに同じ)
ヒアドキュメント
my ($world, $perl) = qw(World Perl);

print <<EOS;
Hello\t$world!
Hello\t$perl!
@@@
EOS

print <<"EOS";
Hello\t$world!
Hello\t$perl!
@@@
EOS

print <<'EOS';
Hello\t$world!
Hello\t$perl!
@@@
EOS

print <<`EOS`;
uname
uname -a
cat /etc/debian_version
EOS
実行結果
Hello	World!
Hello	Perl!
@@@
Hello	World!
Hello	Perl!
@@@
Hello\t$world!
Hello\t$perl!
@@@
Linux
Linux 55179a8a049f 5.15.0-1017-aws #21~20.04.1-Ubuntu SMP Fri Aug 5 11:44:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
bullseye/sid
この例では、終了文字列を EOS としましたが、EOFなどもよく使われます。
ヒアドキュメントは入れ子にできるので、入れ子レベルに応じた名前を付けることになると思います。

ビット列演算子

編集

任意のサイズのビット列( Bitstring )は、ビット演算子(~ | & ^)で操作することができる。

ビットごとの否定を返します。

ビットごとの論理和(or)を返します。

ビットごとの論理積(and)を返します。

ビットごとの排他的論理和(xor)を返します。

文字列強制版ビット列演算子

編集

オペランドを文字列に強制するバージョンのビット演算子(~. |. &. ^.)です。

オペランドを文字列に強制し、ビットごとの否定を返します。

オペランドを文字列に強制し、ビットごとの論理和(or)を返します。

オペランドを文字列に強制し、ビットごとの論理積(and)を返します。

オペランドを文字列に強制し、ビットごとの排他的論理和(xor)を返します。

シフト演算子

編集

右ビットシフトを行います。

左ビットシフトを行います。

論理演算子

編集

論理演算子は、典型的にはif文などの条件式に使用されますが、短絡評価を行うため制御構造としても機能します。また、||or&&and!not は別名関係にありますが、or,and,notの方が優先順位が低いことに注意してください。"単語よりも演算子らしい記号のほうが強い"と覚えておいてください。

||は、論理和を返す二項演算子です。

use v5.30.0;
use warnings;

my @v = ( 0, 5, !!0, "NaN" ),;
foreach my $x (@v) {
    foreach my $y (@v) {
        say "$x || $y --> @{[ $x || $y ]}";
    }
}
実行結果
0 || 0 --> 0
0 || 5 --> 5
0 ||  --> 
0 || NaN --> NaN
5 || 0 --> 5
5 || 5 --> 5
5 ||  --> 5
5 || NaN --> 5
 || 0 --> 0
 || 5 --> 5
 ||  --> 
 || NaN --> NaN
NaN || 0 --> NaN
NaN || 5 --> NaN
NaN ||  --> NaN 
NaN || NaN --> NaN
0, 5, 真理値偽, 非数の組合わせを試しました。
論理和演算子は、名前と違い真理値ではなくスカラーを返します。
$x || $y
$x ? $x : $y
と等価です

or は、優先度が低いバージョンの || 演算子です。

短絡評価

編集

論理和は左引数が偽である場合のみ右引数の評価を行います。 このような論理演算子の実質的に制御構造としての振る舞いを「短絡評価」とよびます。 論理和はまた、最後に評価された値を返すので例外処理にも使われます。 このとき or の優先度が低いことが役に立ちます。

$success or die;
これは、「成功または死ぬ」あるいは「成功するか死ぬか」と読めます。

&&は、論理積を返す二項演算子です。

use v5.30.0;
use warnings;

my @v = ( 0, 5, !!0, "NaN" ),;
foreach my $x (@v) {
    foreach my $y (@v) {
        say "$x && $y --> @{[ $x && $y ]}";
    }
}
実行結果
0 && 0 --> 0
0 && 5 --> 0
0 &&  --> 0
0 && NaN --> 0
5 && 0 --> 0
5 && 5 --> 5
5 &&  --> 
5 && NaN --> NaN
 && 0 --> 
 && 5 --> 
 &&  --> 
 && NaN --> 
NaN && 0 --> 0
NaN && 5 --> 5
NaN &&  -->  
NaN && NaN --> NaN
0, 5, 真理値偽, 非数の組合わせを試しました。
論理積演算子は、名前と違い真理値ではなくスカラーを返します。
$x && $y
!$x ? $x : $y
と等価です

and は、優先度が低いバージョンの && 演算子です。

論理積も短絡評価を行います。

この // は、正規表現のそれではなく / 2文字からなるトークンで、|| とよく似ていますが、左辺が定義さていれば左辺を、定義されていなければ右辺を返します。オプショナルな引数の定義状況のテストを意図されています。

my $x = defined $opt ? $opt : "no";

my $x = $opt // "no";

と簡素に書くことができます。

// は、5.10 で追加されました。

notは、与えられた論理式の否定を表します。Aが真のとき、not A は偽です。Aが偽のとき、not A は真です。

$x = 2;
if (not $x == 5 ) {
  say "実行された";
}
実行結果
実行された
解説
$x = 2
2 == 5 ⇒ 偽
not 偽 ⇒ 真
∴ not $x == 5 は真
if の条件が真なので、コードブロック実行され say が実行されます。

! は、優先度が高いバージョンの not 演算子です。

数値比較演算子

編集

不等号を表すのに利用します。

if ($x > $y) {
   #この部分は$xが$yより大きいときに実行されます
}

if ($x <= $y) {
 #この部分は$xが$y以下のときに実行されます
}
以上または以下の <= や >= については、最初に不等号の記号が来ます。(Perl にかぎらずC言語など他のプログラム言語でも、同様の順序です。)

比較演算子は数値の他、文字列にも 数学記号の ≦ と <= は同じ意味ですが、パソコンの直接入力(半角英数)には ≦ が無いので、プログラミングでは <= で代用されます。 これは、Cも同様です(PerlがCを模倣したのですが)。 Fortranの様にASCIIコードが制定される前の言語では '<' がキャラクターセットになかったり文字のサポートがまちまちだったので、.EQ.,.NE.,.GT.,.LT.,.GE.,.LE.,.AND.,.OR.,.NOT. のように演算子の頭文字をドット. で囲み表現しました。 Perlの文字列の比較演算子も概ねFortranの記法にならっています。

同じ数値であることや、違う数値であることを表すのに使用されます。両辺の変数などの内容を(文字列ではなく)数値として評価します。

if ($x == $y) {
     # この部分は$xが$yと同じ値のときに実行されます
}

if ($x != $y)) {
     # この部分は$xが$yと違う値のときに実行されます
}

== は、両辺の値が等しい事を要求します。if文の中でよく使います。

(Perlに限らずC言語などでも、)よくあるミスで、「=」と記号をひとつだけにするミスがありますが、これはエラーになるか、または代入演算子として解釈されるのでバグになります。

!= は 両辺の値が等しくない事を要求します。つまり、!= は両辺の値が違っている事を要求します。

等しくない場合の != では、否定の記号 ! が先に来ます。(Perl にかぎらずC言語など他のプログラム言語でも、同様の順序です。)

左右の数値の大小関係により -1, 0, 1 のいずれかを返します。これは主にsortで使われます。

@a = (22, 3, 111);

@a = sort {$a <=> $b} @a;
# この時点で@aは (3, 22, 111) になっています

@a = sort {$b <=> $a} @a;
# この時点で@aは (111, 22, 3) になっています

文字列比較演算子

編集
文字列比較演算子
演算子 意味
A eq B AとBは等しい
A ne B AとBは等しくない
A gt B AはBより大きい
A ge B AはB以上
A lt B AはBより小さい
A le B AはB以下

両辺の文字列が、文字列として評価した場合に、同じ値かを調べるときに使用します。

なお、== および != は両辺が数値として評価した場合なので、意味が違います。

Perlには変数に型が無いので、C言語とは異なり、比較演算子の側で、変数の内容を数値として評価するか、内容を文字列として評価するかの指定が必要になるのです。

if ($x eq $y) {
    # この部分は$xが$yと同じ文字列のときに実行されます
}

if ($x ne 'correct')) {
    # この部分は$xに代入されている文字列が 'correct' でなかったときに実行されます
}

eq は、両辺を文字列として比較したときに、両辺が同じであることを要求します。

なお「eq」とは equal (等号、等しい)の略であるとされる。

ne は、両辺を文字列として比較したときに、両辺が異なることを比較します。

「ne」とは not equal の略だとされる。


二つの文字列の辞書順での大小を比較します。

if ($x le $y) {
     # この部分は$xが$y以下のときに実行されます
}

; le -- less than or equal -- 以下
; ge -- greater than or equal -- 以上
; lt -- less than -- より小さい未満
; gt -- greater than -- より大きい

二つの文字列の辞書順での大小関係により-1, 0, 1のいずれかを返します。これは主にsortで使われます。

@a = ('3', '22', '111', 'z', 'A', 'a', 'Z');

@a = sort {$x cmp $y} @a;
# この時点で@aは ('111', '22', '3', 'A', 'Z', 'a', 'z') になっています

@a = sort {$y cmp $x} @a;
# この時点で@aは ('z', 'a', 'Z', 'A', '3', '22', '111') になっています

条件演算子

編集
条件 ? 式1 : 式2
条件が成立する場合は式1の値を、そうでない場合は式2の値を返します。
$x = 1;
$y = $x ? 'true' : 'false';      # $y には 'true' が代入される

範囲演算子

編集
式1 .. 式2 で範囲を表します。
式1・式2はリテラルである必要はありません。
リストコンテキストの例
#!/usr/bin/env perl
use v5.30.0;
use warnings;

print<<EOS;
1..32 --> @{[ 1..32 ]}
"1".."12" --> @{[ "1".."12" ]}
'a'..'z' --> @{[ 'a'..'z' ]}
'A'..'BE' --> @{[ 'A'..'BE' ]}
'A1'..'D7' --> @{[ 'A1'..'D7' ]}
EOS
実行結果
1..32 --> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
"1".."12" --> 1 2 3 4 5 6 7 8 9 10 11 12
'a'..'z' --> a b c d e f g h i j k l m n o p q r s t u v w x y z
'A'..'BE' --> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE AF AG AH AI AJ AK AL AM AN AO AP AQ AR AS AT AU AV AW AX AY AZ BA BB BC BD BE 
'A1'..'D7' --> A1 A2 A3 A4 A5 A6 A7 A8 A9 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 D0 D1 D2 D3 D4 D5 D6 D7
1..32は、(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32)に展開されます
"1".."12"は、文字列ですが数値として解釈可能なので(1,2,3,4,5,6,7,8,9,10,11,12)に展開されます
'a'..'z'は、マジカルインクリメントで('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')に展開されます
'A1'..'D7'も、マジカルインクリメントですが'A9'から'B0'に桁上りしています


スカラーコンテキストの例
#!/usr/bin/env perl
use v5.30.0;
use warnings;

while (<DATA>) {
    print if 8 .. 10;        # 8行目から10行目を出力
    print if /<head>/ .. /<\/head>/; # head要素の内容を出力
}
__DATA__
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset='utf-8'>
    <title>簡単な例</title>
  </head>
  <body>
    <h1>簡単な例</h1>
    <p>この文書は非常に簡単な例です</p>
  </body>
</html>
実行結果
  <head>
    <meta charset='utf-8'>
    <title>簡単な例</title>
  </head>
    <h1>簡単な例</h1>
    <p>この文書は非常に簡単な例です</p> 
</body>
スカラーコンテキストの場合はフリップフロップ演算子となります。
オペランドが数値の場合は、暗黙に$.(行番号)と比較 (==) を行います。
...演算子を用いた場合は、左オペランドが真となった後、次の行に移ってから右オペランドの評価を行う。

フリップフロップ演算子

編集

フリップフロップ演算子として .. が振る舞うときは癖が強いです

$n == 3 .. $n == 5 ? "1" : "2"
3 <= $n <= 5 ? "1" : "2"

と等価です。

    print if 8 .. 10;        # 8行目から10行目を出力
    print if $. == 8 .. $. == 10;        # 8行目から10行目を出力
と等価で
    print if 8 <= $. <= 10;        # 8行目から10行目を出力

とも等価です。

置換演算子

編集
s/PATTERN/STRING/

PATTERNにマッチするものをSTRINGに置換します。PATTERNは正規表現です。

$str = "Wiki";
$str =~ s/(Wiki)/$1pedia/;
print $str; # Wikipedia

パターン変換演算子

編集

tr/PATTERN1/PATTERN2/ 1文字を対応する1文字に置換します。PATTERNには正規表現ではなく、文字クラス(角括弧で囲まれた文字クラスの[]の内側)を指定します。

tr///
use v5.30.0;
use warnings;

my $str = "ABC BCA CAB";
$str =~ tr/ABC/012/;
say $str;

$str =~ tr/012/AB/;
say $str
実行結果
012 120 201 
ABB BBA BAB
PATTERN1とPATTERN2の長さが違っても(use warnings; しても)警告されず、およそ期待とは違う結果になります。
変換結果に疑問があったら、まずパッターン同士の長さの不一致を疑いましょう。

ハイフンを使って範囲指定を行うことができます。

範囲指定を使ったパターン変換
use v5.30.0;
use warnings;

my $str = "WIKIBOOKS";
$str =~ tr/A-Z/a-z/;
say $str
実行結果
wikibooks

=~ を使わないと $_ の変換対象になり、変換した文字数を返します。

変換した文字数
use v5.30.0;
use warnings;

my $str = "WIKIBOOKS";
local $_ = $str;
say tr/[A-Z]/[A-Z]/;
実行結果
9

リファレンス参照演算子

編集

->は、中置のデリファレンス演算子で、左辺のリファレンスに対し、右辺のフォームによりそれぞれ

[...]
配列
{...}
ハッシュ
(...)
サブルーチン

を参照します。

パターン変換演算子

編集

y/PATTERN1/PATTERN2/ tr///の同義語です。

秘密の演算子

編集

Perl には、秘密の演算子( secret operators )と呼ばれる一連の独特の記法があります[3]。 これらは実際には演算子ではないのですが、高い頻度でコード上に登場するので愛称がつけられたものです。

Perl の秘密の演算子
演算子 愛称 和訳 機能
0+ Venus ビーナス 数値に強制変換
@{[ ]} Baby cart べピーカー リストの展開
!! Bang bang バンバン 論理値化
}{ Eskimo greeting エスキモーの挨拶 ワンライナーでの END ブロック
~~ Inchworm 尺取り虫 スカラーコンテキスト
~- Inchworm on a stick 串刺し尺取り虫 高優先順序のデクリメント
-~ Inchworm on a stick 串刺し尺取り虫 高優先順序のインクリメント
-+- Space station 宇宙ステーション 高優先順序の数値化
=( )= Goatse 山羊 スカラー/リストコンテキスト
=< >=~ Flaming X-Wing 炎上Xウィング マッチ入力、キャプチャの割り当て
~~<> Kite 一行入力
<<m=~m>> m ; Ornate double-bladed sword デコデコした両刃剣 複数行コメント
-=! -=!! Flathead フラットヘッド 条件デクリメント
+=! +=!! Phillips フィリップス 条件インクリメント
x=! x=!! Pozidriv プラスドライバー 条件により '' にリセット
*=! *=!! Torx 星型ドライバー 条件により 0 にリセット
,=> Winking fat comma ウインクする太っちょコンマ non-stringifying fat comma
()x!! Enterprise USSエンタープライズ 論理リスト スカッシュ
0+!! Key to the truth 真理の鍵 数値論理値変換
~~!! Serpent of truth 真理のサーペント 数値論理値変換
||() Abbott and Costello アボットとコステロ リストから偽のスカラーを削除
//() Leaning Abbott and Costello 傾いたアボットとコステロ リストから undef のスカラーを削除

ビーナス演算子は、式を強制的に数値化します。

0+
foreach $x(qw(13b 3.1415926536 1.8e3 0xff 0177 0o177 0b10110), "32 Yen", "one penny", []) {
    print "0+$x -> @{[0+$x]}\n"
}
実行結果
0+13b -> 13
0+3.1415926536 -> 3.1415926536
0+1.8e3 -> 1800
0+0xff -> 255
0+0177 -> 177
0+0o177 -> 0
0+0b10110 -> 0
0+32 Yen -> 32
0+one penny -> 0 
0+ARRAY(0x558699694470) -> 94036587791472
0+ Venus は、式を数値に強制変換します。
加算演算子 + は、両辺を数値に変換してから加算します。
左辺を0に固定したので、単純な右辺の数値への強制変換になります。
秘密の演算子の中では、一番わかりやすく実用価値も高いです。
ただ、やはり組込み関数の int などを使ったほうが、意図がわかりやすく grep 性も高くなります。

Baby cart

編集

ベビーカー演算子は、文字列の内部でリスト補間を行います。リスト項目は、$"の値で区切られます。

@{[ ]}
%engines = (
    "Thomas" => 1,
    "Edward" => 2,
    "Henry" => 3,
    "Gordon" => 4,
    "James" => 5,
);
print <<EOS;
%engines
@{[ %engines ]}
@{[ sort keys %engines ]}
@{[ sort values %engines ]}
EOS
実行結果
%engines
Thomas 1 Gordon 4 Edward 2 Henry 3 James 5
Edward Gordon Henry James Thomas 
1 2 3 4 5
@{[ ]} Baby cart は、まず内側の [ ]で匿名配列のリファレンスを作り、直後にその値を @{ }でデリファレンスしています。
@{[ ]} Baby cart は、式を文字列化します。
@{[ ]} Baby cart は、また書き換え可能なコピーを作り出せます。

[TODO:例]

  1. ^ Operator Precedence and Associativity
  2. ^ 2.0 2.1 Perl5.32から0<= $x && $x < 120<= $x < 12 書けるようになりました。
  3. ^ perlsecret - Perl secret operators and constants