プログラミング > Perl > Perl/関数


関数とサブルーチン

編集

Perlにおいて、「関数」と「サブルーチン」という用語は異なる意味で使われます。まず、「関数」という言葉は主にPerlが提供する組み込み機能、つまり組込み関数を指します。たとえば、printchomplengthといった関数がこれに該当します。これらはPerlの言語仕様にあらかじめ用意されたキーワードであり、特別な処理が施されています。たとえば、printはリスト全体を引数として受け取り、文法的にも他の部分と衝突することなく優先的に認識されます。一方で、組み込み関数は\&を使ってコードリファレンスを取得することができず、別のサブルーチンや無名サブルーチンを使ってラップする必要があります。

これに対して、「サブルーチン」は、ユーザーがsubキーワードを用いて定義するコードブロックを指します。サブルーチンは自由に作成・変更でき、自分で名前を付けて定義することが可能です。たとえば、sub greet { return "Hello, World\n"; }のようにして、独自のサブルーチンを定義できます。そして、このサブルーチンは\&greetのようにコードリファレンスとして取得できるため、他のサブルーチンに引数として渡したり、後から実行したりすることができます。

呼び出し方についても違いがあります。たとえば、組み込み関数とサブルーチンのどちらも引数がない場合には括弧()を省略できます。しかし、サブルーチンの場合には()を省略すると、構文が曖昧になる可能性があるため、可読性の観点から括弧を付けることが推奨されます。一方で、組み込み関数はキーワードとして特別に扱われるため、括弧を省略しても曖昧さが生じにくい設計になっています。

組み込み関数とサブルーチンにはこうした違いがありますが、両者を混在させて使う際には注意が必要です。特に、サブルーチンと同名の組み込み関数を定義すると、意図せず組み込み関数が優先される場合があります。これを避けるためには、名前の付け方や呼び出し方に注意する必要があります。

また、組み込み関数を他のサブルーチンに引数として渡したい場合には、直接渡すことはできないため、無名サブルーチンを用いてラップするのが一般的です。このように、Perlでは「関数」と「サブルーチン」が明確に区別され、それぞれ特有のルールや扱い方があることを理解することが重要です。

組込み関数

編集

Perlの言語コアで予め定義されている関数のことを「組込み関数」と呼びます。printlengthsubstrなどの一般的な関数から、myusedoなどのキーワード的な構文要素に至るまで、広くPerl自身に組み込まれた関数がこれに当てはまります。

基本的な関数

編集

print関数

編集
機能
print関数は、引数で与えられた文字列や文字列のリストを標準出力に出力します。引数が与えられなかったときは $_ が出力されます。
use v5.30.0;
use warnings;

print "Hello, World\n";
print "Hello, Perl\n"
実行結果
Hello, World 
Hello, Perl
print関数は、行末で改行しないので、もし改行をしたい場合には明示的にエスケープシーケンス \n を文字列の末尾に加えます。

say関数

編集

Perl 5.10 から導入されたsay 関数は、行末で改行を行います。これで、都度 \n を文字列末に記述する手間が省けます。

組込み関数 say
use strict;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

use feature "say";
use feature ':5.10';
use v5.10;

say "Hello";
say "Yes!";
say "Boodbye";

my $message = "こんにちは";
say $message;
say を使うには、6-8 行目の use 宣言のいずれか1つが必要です。
use feature "say";
use feature ':5.10';
use v5.10;
  1. use feature "say";
    
    say を名指しで有効化しています。お勧めです。
    1. use feature qw(say switch);
      
      の様に2つ以上を列挙することもできます。
  2. use feature ':5.10';
    
    バージョン 5.10 以降の機能を全て有効にします。手早く動かすためにはいいのですが過剰です。
  3. use v5.10;
    
    意味的には上と同じですが、より簡素です。多分一番多く使われています。
CORE::say
#!/usr/bin/perl
use strict;
use warnings;

CORE::say "Hello world!";
CORE::を前置するとプラグマを使わずに say関数を使うことができます。
ワンライナーや書き捨てのスクリプトに向いています。
CORE はPerlコアルーチンの名前空間です。

文字列に変数や式を埋込む

編集

Perlでは、文字列の中に変数や式を埋め込むことができ、テンプレート言語であるかのような使いかたが出来ます。

length は文字列の長さを返します。
文字列に変数や式を埋込む
use v5.30.0;
use warnings;

my $x = "aeiou";
my $tmp = length $x;
say "length \"$x\" -> $tmp";
say "length \"aeiou\" -> @{[length 'aeiou']}";
say qq(length "aeiou" -> @{[length 'aeiou']});
実行結果
length "aeiou" -> 5
length "aeiou" -> 5 
length "aeiou" -> 5
この様に、(ダブルクォーテーションマーク)に囲まれた文字列の中では $変数 で式の値が、@{[式]} で式の値が文字列に埋込まれます。
厳密に解説するには、スカラーコンテキストとリストコンテキストの説明が必要なのですが、リファレンスなどの説明が必須なので、機会を見て一括して解説します。
qw// 演算子を使うと、変数や式が展開する文字列の中で
(ダブルクォーテーションマーク)ではなく、(シングルクォーテーションマーク)で囲まれた文字列では、変数や式は展開されません。

数学関数

編集
基本的な数学関数
編集

平方根などの数学計算をする関数が用意されています。

最小のピタゴラス数
use v5.20.0;
use warnings;

say "sqrt(3**2 + 4**2) --> @{[sqrt(3**2 + 4**2)]}";

use POSIX "hypot";

say "hypot(3, 4) --> @{[ hypot(3, 4) ]}"
実行結果
sqrt(3**2 + 4**2) --> 5 
hypot(3, 4) --> 5
Perlの組込み関数 sqrt を使って自乗和の平方根を求めています。
自乗は結果がオーバーフローあるいはアンダーフローを起こす可能性があるので、対策された hypot を使うのが定石です。
ですが、Perlの組込み関数にもMathモジュールにも hypot はなく、POSIXモジュールにあります。
この場合、use POSIX "hypot";ではなくuse POSIX;で充分なのですが、POSIXからhypotを持ってきている意外性を伝えるため明示しました。
呼出し側で、POSIX::hypot(3, 4) とするのも刺激的ですが、複数箇所あると鬱陶しいので use 側で対処しました。
hypot.pl
編集

桁あふれ対策と可変引数に対応したPerl版hypotの例。

hypot.pl
use v5.30.0;
use warnings;

use POSIX;

sub hypot {
    my ( $max, $s ) = ( 0, 0 );

    # 最大値を決定する
    for my $n (@_) {
        next      if $n == 0;
        return $n if $n != $n;       # for NaN
        my $arg = abs($n);
        return $arg if $arg == "Inf";# for Inf
        $max = $arg if $max < $arg;
    }

    # 最大値に基づいてスケーリングしつつ加算
    for my $n (@_) {
        next      if $n == 0;
        $s += ($n / $max) ** 2;  # 最大値でスケーリングして加算
    }

    # 結果を返す
    return $max * sqrt($s);
}

if ( $0 eq __FILE__ ) {
    foreach my $i ( -1075 .. -1073, -540 .. -538, 0 .. 2, 508 .. 511, 1021 .. 1024 ) {
        my $j = 2**$i;
        my ( $n, $m ) = ( 3 * $j, 4 * $j );
        say "$i: @{[ 5 * $j ]} @{[ sqrt($n*$n + $m*$m) ]} @{[ ::hypot($n, $m) ]} @{[ POSIX::hypot($n, $m) ]}";
    }
}
実行結果
-1075: 0 0 0 0
-1074: 2.47032822920623e-323 0 2.47032822920623e-323 2.47032822920623e-323
-1073: 4.94065645841247e-323 0 4.94065645841247e-323 4.94065645841247e-323
-540: 1.38922421842817e-162 0 1.38922421842817e-162 1.38922421842817e-162
-539: 2.77844843685635e-162 3.14345556940526e-162 2.77844843685635e-162 2.77844843685635e-162
-538: 5.55689687371269e-162 5.44462475754526e-162 5.55689687371269e-162 5.55689687371269e-162
0: 5 5 5 5
1: 10 10 10 10
2: 20 20 20 20
508: 4.18993997810706e+153 4.18993997810706e+153 4.18993997810706e+153 4.18993997810706e+153
509: 8.37987995621412e+153 8.37987995621412e+153 8.37987995621412e+153 8.37987995621412e+153
510: 1.67597599124282e+154 Inf 1.67597599124282e+154 1.67597599124282e+154
511: 3.35195198248565e+154 Inf 3.35195198248565e+154 3.35195198248565e+154
1021: 1.12355820928895e+308 Inf 1.12355820928895e+308 1.12355820928895e+308
1022: Inf Inf Inf Inf
1023: Inf Inf Inf Inf 
1024: Inf Inf Inf Inf
Perlには、Cの isnan() や isfinite() に相当する関数がないので、それぞれ $n != $nabs($n) == "Inf" としました。
POSIXモジュールにはisfinite関数があるので、それを使えばよいのですが、POSIX::hypotの代替実装なので利用を見送りました。
三角関数など
編集

sin,cos は組込み関数にありますが、tan, acos など他の三角関数や円周率(pi)を使用するには、use宣言を使って Math::Trigモジュールから導入します。

余弦関数と逆余弦関数
use 5.30.0;
use warnings;

use Math::Trig qw(pi acos);

say "cos(pi) -> cos(@{[pi]}) -> @{[cos(pi)]}";
say "acos(-1) ->  @{[acos(-1)]}"
実行結果
cos(pi) -> cos(3.14159265358979) -> -1 
acos(-1) ->  3.14159265358979
円周率は、Math::Trigモジュールを導入すると使えるようになりますが、$piではなく piです。
文字列中で参照する場合は "@{[pi]}" となります。
Perlの三角関数の角度の単位は多くのプログラミング言語同様ラジアン(弧度法)です。
正弦sinと余弦cosはPerlの言語コアで定義されていますが、正接tanはMath::Trigモジュールで定義されています。
Math::Trigモジュールでは、piなどの定数や他の三角関数関連の諸関数が定義されています。

日付時刻関係の関数

編集

現在の日時や時刻などを表すには、time関数およびlocaltime関数を使います。

エポックからの秒数と、ローカル時刻
use v5.30;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());  
say "time() -> @{[time()]}";
say "いまは、@{[1900 + $year]} 年 @{[1 + $mon]} 月 $mday 日 $hour 時 $min 分 $sec 秒です。";

use POSIX "strftime";
say strftime "%Y/%m/%d %H:%M:%S", localtime();
say strftime "%c", localtime();
実行結果
time() -> 1668851859
いまは、2022 年 11 月 19 日 9 時 57 分 39 秒です。
2022/11/19 09:57:39 
Sat 19 Nov 2022 09:57:39 AM UTC
説明
time関数は、エポック(1970年1月1日0時0分0秒(UTC) )からの通算秒を返します。
localtime関数は、エポックからの通算秒形式の引数を、年月日時分秒の要素に分解しリストで返します。
localtime関数は、引数を省略すると time()が仮定されるので、この例での引数は冗長です。
localtimeが返すリストを操作するには1900を足したり月数の補正をしたり面倒です(よく間違えます)。
POSIXモジュールの strftime を使うと、Cのstrftime()と同じ(正確にはPOSIXと同じ)書式化文字列がつかえ可読性も向上します。使いましょう。
DateTimeモジュールもあるのですが、Perl流のオブジェクト指向の構文で書かれているので、直感的とは言い難いコードになります。使うなとまでは言いません。

split関数

編集

split関数には、与えられたパターンで文字列を区切り、リストで返します。

split
use v5.30;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my @list = split(/ /, '睦月 如月 弥生 卯月 皐月 水無月 文月 葉月 長月 神無月 霧月 師走');
for (my $i = 0; $i <= $#list; $i++){
  say qq(@{[$i+1]}月: $list[$i]);
}
実行結果
1月: 睦月
2月: 如月
3月: 弥生
4月: 卯月
5月: 皐月
6月: 水無月
7月: 文月
8月: 葉月
9月: 長月
10月: 神無月
11月: 霧月 
12月: 師走

サブルーチン

編集

Perlでは、ユーザーが定義する関数のことをサブルーチン( subroutine )と呼び、キーワードsubを使い定義します。

シンプルなサブルーチンの定義と呼出し

編集

サブルーチンの定義と呼出しは、説明することがほとんどないほど簡単です。

シンプルなサブルーチンの定義と呼出し
use v5.30.0;
use warnings;

sub world {
    say "Hello, World";
}

sub perl {
    say "Hello, Perl";
}

&world;
&perl;

world;
perl;
実行結果
Hello, World
Hello, Perl
4-6がサブルーチンworldの定義
8-10がサブルーチンperlの定義
見たままです
12,15 がサブルーチンworldの呼出し
13,16 がサブルーチンperlの呼出し
見たままですが、&が前置されていなくても、されていても同じというのは釈然としません。
この & は、組込み関数では前置できません。
というわけで、& を関数呼出しで前置するのは、「組込み関数ではなくサブルーチンを呼んでいます」という意味になります。
また、& を省略するとサブルーチンの宣言より前に、サブルーチンを呼出すことはできません。

サブルーチン宣言

編集

サブルーチンの定義より先にサブルーチンを呼出す必要があることがあります(典型的には、お互いに呼び合う関数)。 この場合は、呼出ごとに & を前置するか、サブルーチン宣言をサブルーチン呼出の前にします。

サブルーチン宣言
use v5.30.0;
use warnings;

&world;
&perl;

sub world;
world;

sub perl;
perl;

sub world {
    say "Hello, World";
}

sub perl {
    say "Hello, Perl";
}
実行結果
Hello, World
Hello, Perl
Hello, World 
Hello, Perl
4,5は & を前置しているので、宣言がなくてもサブルーチンとわかる。
7,10がサブルーチン宣言で、サブルーチン定義の前方参照を解決します。

グローバル変数を使ったサブルーチンの振る舞いの変更

編集

前出の例は、ほとんど同じ内容のサブルーチンを2つ用意しましたが、1つにまとめてみましょう。

グローバル変数を使ったサブルーチンの振る舞いの変更
use v5.30.0;
no strict;
use warnings;

$who = "WHO!";

sub hello {
    say "Hello, $who";
}

&hello;
$who = "world";
&hello;
$who = "Perl";
&hello;
実行結果
Hello, WHO!
Hello, world 
Hello, Perl
グローバル変数 $who を使ってメッセージの後半を変えています。
この方法はこの方法で動きますし、かつてのFORTRANやBASICは、まさにこのようにグローバル変数でサブルーチンをコントロールしていました。
しかし、2行目のno strict;で明示的に strict を無効にしなければエラーが出るほど、グローバル変数の使用は推奨されない方法です。

引数を使ったサブルーチンの振る舞いの変更

編集

前出の例は、グローバル変数を使っていましたが、グローバル変数はデーターフロー的なスパゲティーコードに直結するので、引数を使ってスマートに実装してみましょう。

引数を使ったサブルーチンの振る舞いの変更
use v5.30.0;
use warnings;

sub hello {
    my $who = shift;
    $who //= "WHO?!";
    say "Hello, $who";
}

&hello();
&hello("world");
&hello("Perl");
実行結果
Hello, WHO?!
Hello, world 
Hello, Perl
引数の受け取り
my $who = shift;
Perlのサブルーチンの引数は、名前を持った仮引数ではなく特殊変数 @_ に配列として渡されます。
第一引数が $_[0] となります。
半ば定型文なのですが、引数を左から順に読む動作が shift(shift @_ の意味) と符合するので、それらしい名前(この場合は $who)の変数を宣言し shift で初期化するコードが良く見られます。
キーワード my を前置して宣言した変数は、「レキシカル変数」となり、サブルーチン(この場合は hello)を抜けると参照できなくなり、もう一度同じサブルーチンを呼んでも、もう違う値になってます(非永続的なレキシカルスコープ)。
ディフォルト引数
$who //= "WHO?!";
Perlには、ディフォルト引数の構文はなかったので、引数が渡されなかった場合の既定値(ディフォルト)を指定するには、このようなイディオムになります。

この @_ による引数の受渡しは、Perlでは約20年に渡って使われてきましたが、他のプログラミング言語のように名前付きの仮引数が欲しいとの要望は根強く、シグネチャーとしてv5.20.0から実験的な機能として実装されています。

戻値と再帰

編集

ここまでで、引数を受取りサブルーチンの振舞いを変えることができるようになりました。 次に、「値を返す手段」が問題になります。 グローバル変数を使って値を返せそうですが「データーフロー的なスパゲティーコード」になるのでサブルーチンの「戻値」を使ってみましょう。

戻値を返すサブルーチン

編集

いままでのサブルーチンは値を返しませんでしたが、Perlのサブルーチンは値を1つ返すことができます。

戻値を返すサブルーチン
use strict;
use warnings;

sub add {
    my ($x, $y) = @_;
    return $x + $y;
}

print("add(12, 9) -> @{[add(12, 9)]}\n");
print("add(1.2, 0.9) -> @{[add(1.2, 0.9)]}\n");
print("add(123, '89') -> @{[add(123, '89')]}\n");
実行結果
add(12, 9) -> 21
add(1.2, 0.9) -> 2.1 
add(123, '89') -> 212
戻値を返す文
return $x + $y;
Perlのサブルーチンの戻値を返す場合は
return
return  ;
での「式」の値が返ります。
もし return のないサブルーチンの戻値を参照すると、サブルーチンで最後に評価した式の値がかえります。このため
return $x + $y;
$x + $y;
と同じです。
Perl の ; は、Cのように式を文にするのではなく、式と式を区切るデリミターなので最後の式の後に ; は不要です。
戻値とは関係ありませんが、
文字列が数値に自動変換される
print("add(123, '89') -> @{[add(123, '89')]}\n");
が、何事もなかったかのように
add(123, '89') -> 212
となるように、数値が期待されす文脈に数値に変換できる文字列が来ると、自動的に数値に変換され演算されます。
Perlのこの暗黙の変換は、エポックからの通算秒が桁上りしたときなどに発現する凶悪なバグの原因になってきました。

再帰的呼出し

編集

引数と戻値が手に入ったので、再帰的呼出しを行うサブルーチンを書いてみます。

整数の冪乗
編集

整数の累乗を返すサブルーチン pow を書いてみました。

整数の冪乗
use v5.30.0;
use warnings;

sub pow {
    my ($n, $m) = @_;
    return "Domain error" if $m < 0;
    return 1 if $m == 0;
    return $n if $m == 1;
    return $n * &pow($n, $m - 1);
}

say "pow(2, $_) -> @{[ pow(2, $_) ]}" foreach -1..3;
実行結果
pow(2, -1) -> Domain error
pow(2, 0) -> 1
pow(2, 1) -> 2
pow(2, 2) -> 4 
pow(2, 3) -> 8
9 で、pow自身を指数を1減らして呼んでいます。
$n, $m が重複使用されているように見えますが、myがついているので、再帰レベルが1つ下るごとに別のインスタンスが生成されています。
整数を3桁ごとにカンマで区切って表示する
編集

整数を3桁ごとにカンマで区切って表示するサブルーチン comma3 を書いてみました。

整数を3桁ごとにカンマで区切って表示する
use v5.30.0;
use warnings;

sub comma3 {
    my $n = shift;
    return "-" . comma3(-$n) if $n < 0;
    my ($num, $rem) = (int($n / 1000), $n % 1000);
    return comma3($num) . sprintf ",%3d", $rem if $num;
    return sprintf "%d", $rem
}

say comma3 $_ foreach qw(
    123456789 
    -999999 
    0 
    1 
    12 
    123 
    1234
)
実行結果
123,456,789
-999,999
0
1
12
123
1,234
フィボナッチ数列とメモ化とベンチマーク
編集

再帰で必ず取上げられるフィボナッチ数列とメモ化を題材に、ベンチマークテストを行ってみようと思います。

フィボナッチ数列とメモ化とベンチマーク
use v5.30.0;
use warnings;

sub fibonacci {
    my $n = shift;
    return $n if $n == 0;
    return $n if $n == 1;
    return fibonacci($n - 2) + fibonacci($n - 1)
}

sub fibonacci_norec {
    my $n = shift;
    my ($x, $y) = (1, 0);
    ($x, $y) = ($y, $x + $y) foreach 1..$n;
    return $y
}

sub fibonacci_memorization {
    my $n = shift;
    state @table = (0, 1);
    return $table[$n] if defined $table[$n]; 
    return $table[$n] = fibonacci($n - 2) + fibonacci($n - 1)
}

use Benchmark qw/timethese cmpthese/;
my $i = 16;
cmpthese timethese(2 ** 10, {
  "再帰"   => sub { fibonacci($_) foreach 1..$i },
  "非再帰" => sub { fibonacci_norec($_) foreach 1..$i },
  "メモ化" => sub { fibonacci_memorization($_) foreach 1..$i },
});
実行結果
Benchmark: timing 1024 iterations of メモ化, 再帰, 非再帰...
 メモ化:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)
            (warning: too few iterations for a reliable count)
    再帰:  2 wallclock secs ( 1.58 usr +  0.00 sys =  1.58 CPU) @ 648.10/s (n=1024)
 非再帰:  0 wallclock secs ( 0.01 usr +  0.00 sys =  0.01 CPU) @ 102400.00/s (n=1024)
            (warning: too few iterations for a reliable count)
                           Rate              再帰         非再帰  メモ化
再帰                    648/s                  --              -99%      -100%
非再帰              102400/s              15700%                --      -100% 
メモ化 1023999999999999872/s 157999999999999968% 1000000000000001%         --
fibonacci は、素朴な再帰版のフィボナッチ数列です。
fibonacci_norec は、非再帰版のフィボナッチ数列です。
fibonacci_memorization は、メモ化を施した再帰版のフィボナッチ数列です。
20行目の state @table = (0, 1);は、非揮発性のレキシカルスコープ変数の宣言で、 my と違い最初しか初期化されず、再び同じサブルーチンを呼ばれたときには前の値を憶えています。またサブルーチンの外から参照する方法はありません。
メモ化は、一度計算した答えを記憶して次からは記憶から答える戦略なので、ベンチマークに有利です。
メモ化を行うアルゴリズムと行なわないアルゴリズムでは、ベンチマークのような繰り返しに関する感受性が違います。繰返し回数に対し線形に時間が増えないアルゴリズムはメモ化を行っている可能性があるので、ループの底で使われるのには適していますが、頻度の低い使い方の場合、性能が予想より悪い可能性があります。
このことから、実際のプログラムのプロファイル結果とベンチマークの結果の傾向の比較も重要になります。
無名再帰
編集

サブルーチン自身へのリファレンス __SUB__ を使うと無名関数の再帰ができます。

整数の冪乗
use v5.30.0;

# 階乗 n!
say (sub {
    my $n = shift;
    return $n == 0 ? $n
         : $n == 1 ? $n
         : $n * __SUB__->( $n - 1 );
}->(7));
実行結果
5040

シグネチャー

編集

前出の例で、引数を使ってサブルーチンの振る舞いを変えることができました。

機能的には充足しているのですが、名前付きの仮引数を望む声は以前からあり、Perl 5.20.0 から「実験的」( experimental )なシグネチャーの実装が行なわれ、Perl 5.26.0 からコア機能の1つとなりました。

シグネチャー
# !/usr/bin/perl
use v5.30;
use feature 'signatures';
no warnings "experimental::signatures";
 
sub hello($who = "WHO?!") {
    say "Hello, $who";
}

&hello();
&hello("world");
&hello("Perl");
実行結果
Hello, WHO?!
Hello, world 
Hello, Perl
シグネチャー
sub hello($who = "WHO?!") {
名前を持った仮引数が使えるようになりました。
ディフォルト引数にも対応しています。
Perl 5.36.0 からは、signatures は experimental を卒業したので
use v5.30;
use feature 'signatures';
no warnings "experimental::signatures";
use v5.36.0;
とできます(使用している処理系が、v5.30.0以降の場合に限ります)。

プロトタイプ

編集

ラムダ抽象

編集

sort のように、コードブロックを引数とするサブルーチンを考えてみましょう。

use v5.30.0;

sub bis(&) {
    my $cbr = shift;
    $cbr->();
    $cbr->()
}
bis { say 'Hello, world!' };

my $i = 0;
bis { $i++ };
say $i;
実行結果
Hello, world!
Hello, world! 
2
与えられたコードブロックを2回実行するサブルーチンです。
3行目のsub bis(&)&はラムダ抽象です。

map を模倣

編集

組込み関数 map を模倣したサブルーチン mapx を実装します。

use v5.30.0;

sub map(&@) {
    my ( $cbr, @ary ) = @_;
    my @result;
    push @result, $cbr->( local $a = $_ ) foreach @ary;
    return @result;
}
say main::map { 2 * $_ } ( 1, 2, 3 );
say main::map { 2 * $a } ( 1, 2, 3 );
say CORE::map { 2 * $_ } ( 1, 2, 3 );
say main::map { $_ x 2 } qw(a b c);
say main::map { $a x 2 } qw(a b c);
say CORE::map { $_ x 2 } qw(a b c);
実行結果
246
246
246
aabbcc
aabbcc 
aabbcc
組込み関数 sort の様に、$a でコードブロックに引数を渡すこともできるようにしました。
local で宣言しているので、スコープは foreach 式の中だけで、抜けるとグローバルな $a は埋戻されます。

reduce

編集

組込み関数に reduce がなかったので実装しました。

use v5.30.0;
use warnings;

sub reduce(&@) {
    my ( $cbr, @ary ) = @_;
    my $init = shift @ary;
    $init = $cbr->( local $a = $init, local $b = $_ ) foreach @ary;
    return $init;
}

say reduce { $_[0] + $_[1] } 1 .. 10;
say reduce { $_[0] . $_[1] } "A" .. "Z";
say reduce { $a + $b } 1 .. 10;
say reduce { $a . $b } "A" .. "Z";
実行結果
55 
ABCDEFGHIJKLMNOPQRSTUVWXYZ
55 
ABCDEFGHIJKLMNOPQRSTUVWXYZ
組込み関数 sort の様に、$a$b でコードブロックに引数を渡すこともできるようにしました。

filter

編集

組込み関数に grep は、多くの言語で filter の名前で知られる関数です。

use v5.30.0;

sub filter(&@) {
    my ( $cbr, @ary ) = @_;
    my @result = ();
    $cbr->( local $a = $_ ) ? push( @result, $_ ) : 0 foreach @ary;
    return @result;
}
say filter { $_ % 2 == 1; } 1 .. 10;
say filter { $a % 2 == 1; } 1 .. 10;
say grep { $_ % 2 == 1; } 1 .. 10;
say filter { index( "Hello world", $_ ) >= 0 } ( "A" .. "Z", "a" .. "z" );
say filter { index( "Hello world", $a ) >= 0 } ( "A" .. "Z", "a" .. "z" );
say grep { index( "Hello world", $_ ) >= 0 } ( "A" .. "Z", "a" .. "z" );
say "@{[ map { $_ * 2 } filter { $_ % 2 == 1; } 1..10]}";
say "@{[ map { $_ * 2 } filter { $a % 2 == 1; } 1..10]}";
say "@{[ map { $_ * 2 } grep { $_ % 2 == 1; } 1..10]}";
実行結果
13579
13579
13579
Hdelorw
Hdelorw
Hdelorw
2 6 10 14 18
2 6 10 14 18 
2 6 10 14 18
組込み関数 sort の様に、$a でコードブロックに引数を渡すこともできるようにしました。

コードリファレンス

編集

コードリファレンスとは?

編集

Perlにおいて「コードリファレンス」とは、サブルーチンへの参照(ポインタ)を指します。通常、サブルーチンはその名前を使って呼び出しますが、名前ではなくリファレンス(参照)として扱うことで、動的にサブルーチンを渡したり、配列やハッシュに格納して柔軟に操作することができます。

コードリファレンスの生成

編集

サブルーチンのリファレンスを生成するには、\&を使います。以下はその例です。

sub greet {
    return "Hello, World!\n";
}

my $greet_ref = \&greet;  # サブルーチンのリファレンスを取得

ここで、$greet_refgreetというサブルーチンへの参照を保持するスカラ変数になります。

コードリファレンスの呼び出し

編集

コードリファレンスを呼び出すには、->演算子を使用します。または、&を使うことでも呼び出せます。

# 例: コードリファレンスを使用してサブルーチンを呼び出す
print $greet_ref->();  # Hello, World!

# & を使っても同様
print &$greet_ref();  # Hello, World!

コードリファレンスを使う利点

編集
  1. 柔軟性: サブルーチンを動的に渡せるため、特定の条件に応じて異なるサブルーチンを実行するようなコードが書けます。
  2. データ構造との組み合わせ: 配列やハッシュにサブルーチンのリファレンスを格納することで、複数のサブルーチンを一括管理できます。
sub greet { return "Hello, World!\n"; }
sub farewell { return "Goodbye, World!\n"; }

# ハッシュでサブルーチンリファレンスを管理
my %actions = (
    greet => \&greet,
    farewell => \&farewell,
);

# 動的にサブルーチンを選んで実行
print $actions{greet}->();    # Hello, World!
print $actions{farewell}->(); # Goodbye, World!

無名サブルーチン

編集

コードリファレンスは、無名サブルーチン(名前を持たないサブルーチン)を生成する際にも使用されます。無名サブルーチンはsubキーワードだけで定義され、直接リファレンスとして利用できます。

my $say_hello = sub { return "Hello from anonymous sub!\n"; };

# コードリファレンスとして呼び出す
print $say_hello->();  # Hello from anonymous sub!

コードリファレンスの利用例

編集
サブルーチンの引数として渡す
編集

コードリファレンスを使うことで、サブルーチンを引数として別のサブルーチンに渡すことができます。

sub execute_function {
    my ($func_ref) = @_;
    print $func_ref->("Executing function!\n");
}

# 無名サブルーチンを渡す
execute_function(sub { print @_ });
イベント処理
編集

イベント駆動型プログラミングやコールバック処理で、特定のタイミングで実行するサブルーチンを指定する場合に役立ちます。

sub on_event {
    my ($callback) = @_;
    print "Event occurred!\n";
    $callback->();
}

on_event(sub { print "Callback executed!\n" });
ディスパッチテーブル
編集

関数の実行を名前で動的に選択する「ディスパッチテーブル」を構築する際に利用されます。

sub add { return $_[0] + $_[1]; }
sub subtract { return $_[0] - $_[1]; }

my %dispatch = (
    add => \&add,
    subtract => \&subtract,
);

my $operation = 'add';
print $dispatch{$operation}->(10, 5);  # 15

まとめ

編集

コードリファレンスは、サブルーチンをリファレンスとして動的に扱える仕組みです。これにより、柔軟で再利用性の高いコードを記述できるようになります。特に、動的な処理やコールバックを必要とする場面では非常に有用です。また、無名サブルーチンを利用することで、簡潔で用途に応じたコードが書けるようになります。


[TODO:スコープルールに関する簡素な説明]

[TODO:コンテキストに関する例をふんだんに使った解説]

永続的スコープのレキシカル変数

編集

my で宣言した変数(レキシカル変数)はサブルーチンを抜けると御破算になりますが、state で宣言した変数はレキシカルスコープであるものの次にサブルーチンが呼ばれたときも値を憶えています。

state $var
#!/usr/bin/perl
use v5.10;

sub func {
    my $myVar = 0;
    state $stateVar = 0;
    $myVar++;
    $stateVar++;
    CORE::say "\$myVar = $myVar, \$stateVar = $stateVar";    
}

&func for 1..5
実行結果
$myVar = 1, $stateVar = 1
$myVar = 1, $stateVar = 2
$myVar = 1, $stateVar = 3
$myVar = 1, $stateVar = 4
$myVar = 1, $stateVar = 5
state $var は、Perl 5.10 以降でサポートされています。

コンテキストとwantarray関数

編集

同じサブルーチンを呼出しても、スカラーが戻ることを期待している文脈(スカラーコンテキスト)と、リストが戻ることを期待している文脈(リストコンテキスト)の2通りがあります。 この2つのケースを判別するために wantarray 関数が用意されています。

コンテキストとwantarray関数
#!/usr/bin/perl
use strict;
use warnings;

sub func {
    return map { $_ * 2 } @_ if wantarray();
    my $sum = 0;
    $sum += $_ for @_;
    return $sum;
}

my @x = func(0, 1, 2);
my $y = func(0, 1, 2);
print <<EOS;
my \@x = func(0, 1, 2); \@x -> @x
my \$y = func(0, 1, 2); \$y -> $y
@{[ func(1,2,3) ]}
@{[ scalar func(1,2,3)]}
@{[ ~~ func(1,2,3)]}
EOS
実行結果
my @x = func(0, 1, 2); @x -> 0 2 4
my $y = func(0, 1, 2); $y -> 3
2 4 6
6 
6
wantarray 関数は、サブルーチンを呼出したコンテキストで戻値としてリストが要求されているなら真を、スカラーが要求されているなら偽を返します。
関数 func は、リストコンテキストでは全ての要素を二倍にしたリストを、スカラーコンテキストでは全ての要素の合計を返します。

組込み関数の一覧

編集

文字列:String

編集

chomp chop chr crypt fc hex index lc lcfirst length oct ord pack q/STRING/ qq/STRING/ reverse rindex sprintf substr tr/// uc ucfirst y///

書式
index STR, SUBSTR [, POSITION]</syntaxhighlight copy>
;機能:<syntaxhighlight lang=text>文字列STRの中で部分文字列SUBSTRが最初に出現する位置を返します
組込み関数 index
#!/usr/bin/env perl
use v5.30.0;
use warnings;

my $str = "This is a pen.";
my $substr = "pen";
say qq(index "$str", "$substr" -> @{[index $str, $substr]});

$str = "これは、ペンです。";
$substr = "ペン";
say qq(index "$str", "$substr" -> @{[index $str, $substr]});

use Encode qw(encode decode);

$str = decode('utf-8', "これは、ペンです。");
$substr = decode('utf-8', "ペン");
say encode('utf-8', qq(index "$str", "$substr" -> @{[index $str, $substr]}));
実行結果
index "This is a pen.", "pen" -> 10 
index "これは、ペンです。", "ペン" -> 12  
index "これは、ペンです。", "ペン" -> 4
pen の前にある This is a は空白も含めて合計で10文字なので、10 が表示されます。
文字列とインデックスの対応
0 1 2 3 4 5 6 7 8 9 10 11 12 13
T h i s   i s   a   p e n .
解説
indexは、文字列 STR の中から、検索文字列 SUBSTR を探し、最初に見つかった位置を返します。検索文字が見つからない場合には、-1 が返ります。
省略可能な引数、POSITION には、検索開始位置を指定します(ディフォルトは0)。
POSITION を使うと部分文字列が2回め以降に出現する位置も確かめることが出来、部分文字列の長さに注意すれば部分文字列の出現回数を数えることなどが容易になります。
位置が 0 から始まることに留意しましょう。 0 は文字列の左端を表します。
位置は文字単位ではなくバイト数なので、ソースコードエンコーディングが UTF-8 で多バイト文字が交じると、文字数とバイト数に食い違いが生じます。
このような場合は Encode モジュールを使い内部形式( internal format )に変換します。
内部形式であれば、サロゲートペアにも対応できますが、合成文字は修飾コードと基底文字はそれぞれ1文字に数えられます。
utf8プラグマを使う
編集
別解(utf8プラグマを使う)
#!/usr/bin/perl
use v5.30.0;
use warnings;
use utf8;

my $str = "This is a pen.";
my $substr = "pen";
say qq(index "$str", "$substr" -> @{[index $str, $substr]});

use Encode qw(encode);

$str = "これは、ペンです。";
$substr = "ペン";
say encode('utf-8', qq(index "$str", "$substr" -> @{[index $str, $substr]}));
実行結果
index "This is a pen.", "pen" -> 10  
index "これは、ペンです。", "ペン" -> 4
utf8プラグマを使い、ソースコードエンコーディングが UTF-8 であることを明示すると、文字リテラルは内部形式に変換され index や length で処理されます。
この場合でも、出力するときに内部形式から UTF-8 にエンコードする必要があります。
binmodeを使う
編集
別解(binmodeを使う)
#!/usr/bin/perl
use v5.30.0;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my $str = "This is a pen.";
my $substr = "pen";
say qq(index "$str", "$substr" -> @{[index $str, $substr]});

$str = "これは、ペンです。";
$substr = "ペン";
say qq(index "$str", "$substr" -> @{[index $str, $substr]});
実行結果
index "This is a pen.", "pen" -> 10  
index "これは、ペンです。", "ペン" -> 4
毎回エンコードせず、STDOUT のディフォルトエンコーディングを UTF-8 にかえました。
binmode STDIN,":encoding(UTF-8)";binmode STDERR,":encoding(UTF-8)";も同時に指定したほうがいいかもしれません。

テキストのエンコーディングは、Perlを使っていると度々トラブルのもとになるので、回避方法が幾つかある事を知っておくと、他人の書いたコードを読むときなどに役に立ちます。 ここで紹介した方法の他に、歌代さんのjcode.plなどもあるのですが、標準モジュールの範囲の説明に留めました。

rindex

編集
書式
rindex (STR, SUBSTR, [POSITION])</syntaxhighlight copy>
;機能:文字列STRの中で部分文字列SUBSTRが'''最後'''に出現する位置を返します
;[https://paiza.io/projects/BcE2R3K_lHUDlhNTQWwY3Q?language=perl 組込み関数 rindex]:<syntaxhighlight lang=perl copy>
#!/usr/bin/perl
use v5.30.0;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my $str = "I like pens and pencils.";
my $substr = "pen";
say qq(rindex "$str", "$substr" -> @{[rindex $str, $substr]});

$str = "私は筆と鉛筆が好きです。";
$substr = "筆";
say qq(rindex "$str", "$substr" -> @{[rindex $str, $substr]});
実行結果
rindex "I like pens and pencils.", "pen" -> 16  
rindex "私は筆と鉛筆が好きです。", "筆" -> 5
解説
rindexは、文字列 STR の中から、検索文字列 SUBSTR を探し、最後に見つかった位置を返します(「末尾からの位置を返す」との編集が過去にありましたが、間違いです)。検索文字が見つからない場合には、-1 が返ります。
省略可能な引数、POSITION には、検索開始位置を指定します(ディフォルトは0)。

substr

編集
書式
substr (EXPR, OFFSET, [LENGTH], [REPLACEMENT])</syntaxhighlight copy>

文字列 EXPR からOFFSET 目以降のバイト列を返します取り出す長さ LENGTH をバイト単位で指定できますが省略した場合は文字列の最後まで取り出しますなおutf8プラグマが有効な場合はバイト単位ではなく文字単位で取り出すことができます

位置情報 OFFSET は上述のとおり 0 から始まりますがLENGTH は容量なので通常は 1 以上の値を指定します

文字列 REPLACEMENT を指定すると取り出される部分を REPLACEMENT で置換します

;[https://paiza.io/projects/BcE2R3K_lHUDlhNTQWwY3Q?language=perl 組込み関数 rindex]:<syntaxhighlight lang=perl copy>
#!/usr/bin/perl
use v5.30.0;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my $str = "Hello, world!";
say substr($str, index($str, "world"), length("world"), "Japan");
say $str;

$str = "こんにちは、世界!";
say substr($str, index($str, "世界"), length("世界"), "🌍");
say $str;
実行結果
world
Hello, Japan!
世界 
こんにちは、🌍!
書式
uc ([EXPR])</syntaxhighlight copy>
:文字列 EXPR を大文字にして返しますEXPR を省略すると$_ が使われます

==== ucfirst ====
;書式:<syntaxhighlight lang=perl>ucfirst ([EXPR])</syntaxhighlight copy>
:uc と同じですが先頭1文字を大文字にして返します

==== lc ====
;書式:<syntaxhighlight lang=perl>lc ([EXPR])</syntaxhighlight copy>
:uc と同じですが小文字にして返します

==== lcfirst ====
;書式:<syntaxhighlight lang=perl>lcfirst ([EXPR])</syntaxhighlight copy>
:ucfirst と同じですが小文字にして返します

==== chop ====
;書式:<syntaxhighlight lang=perl copy>
chop VARIABLE
chop (LIST)
変数 VARIABLE の末尾の末尾1文字を削除します。
変数のリストを渡された場合は、各変数について同じ処理を行います。
VARIABLE を省略すると $_ が使われます。
chopとchomp
#!/usr/bin/perl
use v5.30.0;
use warnings;
use utf8;
binmode STDOUT,":encoding(UTF-8)";

my $str = "Hello, world!\n";
chop $str;
say "chop: $str(@{[length $str]})";
chop $str;
say "chop: $str(@{[length $str]})";
chop $str;
say "chop: $str(@{[length $str]})";
chop $str;
say "chop: $str(@{[length $str]})";

$str = "Hello, world!\n";
chomp $str;
say "chomp: $str(@{[length $str]})";
chomp $str;
say "chomp: $str(@{[length $str]})";
chomp $str;
say "chomp: $str(@{[length $str]})";
chomp $str;
say "chomp: $str(@{[length $str]})";

$str = "Hello, world!\n";
$str = substr($str, 0, length($str) - 1);
say "substr(): $str(@{[length $str]})";
$str = substr($str, 0, length($str) - 1);
say "substr(): $str(@{[length $str]})";
$str = substr($str, 0, length($str) - 1);
say "substr(): $str(@{[length $str]})";

sub chop(\$) {
    my $strr = shift;
    $$strr = substr($$strr, 0, length($$strr) - 1);
    undef
}

$str = "Hello, world!\n";
::chop $str;
say "::chop: $str(@{[length $str]})";
::chop $str;
say "::chop: $str(@{[length $str]})";
::chop $str;
say "::chop: $str(@{[length $str]})";

sub chomp(\$) {
    my $strr = shift;
    $$strr = substr($$strr, 0, length($$strr) - 1) if substr($$strr, length($$strr) - 1, 1) eq "\n";
    undef
}

$str = "Hello, world!\n";
::chomp $str;
say "::chomp: $str(@{[length $str]})";
::chomp $str;
say "::chomp: $str(@{[length $str]})";
実行結果
chop: Hello, world!(13)
chop: Hello, world(12)
chop: Hello, worl(11)
chop: Hello, wor(10)
chomp: Hello, world!(13)
chomp: Hello, world!(13)
chomp: Hello, world!(13)
chomp: Hello, world!(13)
substr(): Hello, world!(13)
substr(): Hello, world(12)
substr(): Hello, worl(11)
::chop: Hello, world!(13)
::chop: Hello, world(12)
::chop: Hello, worl(11)
::chomp: Hello, world!(13) 
::chomp: Hello, world!(13)
chop は、文字列を末尾から喰います(破壊的)
chomp は、文字列の末尾の改行を喰います(破壊的)
書式
chomp VARIABLE
chomp (LIST)
変数 VARIABLE の末尾の $/(デフォルトは "\n")を削除します。
変数のリストを渡された場合は、各変数について同じ処理を行います。
VARIABLE を省略すると $_ が使われます。
書式
chr [NUMBER]</syntaxhighlight copy>
: 文字セットで NUMBER 番目に割り当てられている文字を返します
: NUMBER を省略すると $_ が使われます
: 逆の操作を行うには ord を使います

==== crypt ====
;書式:<syntaxhighlight lang=perl>crypt PLAINTEXT, SALT</syntaxhighlight copy>
:C ライブラリの crypt(3) をエミュレートします

==== hex ====
;書式:<syntaxhighlight lang=perl>hex [EXPR]</syntaxhighlight copy>
: 十六進数 EXPR を十進数に変換して返しますEXPR を省略すると $_ が使われます

==== length ====
;書式:<syntaxhighlight lang=perl>length [EXPR]</syntaxhighlight copy>
: 文字列 EXPR の長さを返しますbytes プラグマが有効な場合デフォルトはバイト数をutf8 プラグマが有効な場合は文字数を返しますEXPR を省略すると $_ が使われます

==== oct ====
;書式:<syntaxhighlight lang=perl>oct [EXPR]</syntaxhighlight copy>
: 八進数 EXPR を十進数に変換して返しますEXPR を省略すると $_ が使われます

==== ord ====
;書式:<syntaxhighlight lang=perl>ord [EXPR]</syntaxhighlight copy>
: 文字列 EXPR の文字セット上でのコード位置を返しますEXPR を省略すると $_ が使われます逆の操作を行うには chr を使います

==== pack ====
<code>pack</code>関数は指定されたフォーマットに従ってデータをバイナリ文字列にパックします主にバイナリデータを処理する際に使用されます以下は<code>pack</code>関数の基本的な使用例と一般的なフォーマット指定子の一部です

:<syntaxhighlight lang=perl copy>
# バイナリ文字列を作成する例
my $binary_data = pack('C4 A4', 65, 66, 67, 68, 'Hello');

# 上記の例では、'C4'は4つのバイトの符号なし整数を、'A4'は4バイトの文字列を表します。
# したがって、65, 66, 67, 68はバイナリデータにパックされ、それに続く'Hello'もパックされます。

# バイナリ文字列を出力する
print "$binary_data\n";  # 出力例: ABCDHello

# バイナリ文字列からデータをアンパックする例
my ($num1, $num2, $string) = unpack('C4 A4', $binary_data);

print "$num1 $num2 $string\n";  # 出力例: 65 66 Hello

一般的なフォーマット指定子の一部は以下の通りです。

  • A - 文字列
  • C - 符号なし8ビット整数 (1 バイト)
  • S - 符号なし16ビット整数 (2 バイト)
  • L - 符号なし32ビット整数 (4 バイト)
  • n - ネットワークバイトオーダー (big-endian) の16ビット整数
  • N - ネットワークバイトオーダーの32ビット整数
  • v - リトルエンディアンバイトオーダーの16ビット整数
  • V - リトルエンディアンバイトオーダーの32ビット整数

pack関数とunpack関数は、バイナリデータを他の形式に変換する際に非常に便利です。

q/STRING/
qq/STRING/
qr/STRING/
qx/STRING/
qw/STRING/

シングルクォート、ダブルクォート、正規表現、バッククォート、単語クォート。詳細は演算子の章を参照。

reverse

編集
書式
reverse LIST</syntaxhighlight copy>
:リストコンテキストでは LIST の順番を逆順にしたリストを返しますスカラーコンテキストでは LIST の要素を結合した後に逆順にした文字列を返します
;[https://paiza.io/projects/m274vBmTsDDTfyB1yKQy3g?language=perl ]:<syntaxhighlight lang=perl copy>
use v5.30.0;
use warnings;

my @array = qw(あい うえお かきくけこ 🏝);
say "@{[ reverse @array ]}";
say "@{[ scalar reverse @array ]}";

use utf8;
binmode STDOUT,":encoding(UTF-8)";
@array = qw(あい うえお かきくけこ 🏝);
say "@{[ reverse @array ]}";
say "@{[ scalar reverse @array ]}";
実行結果
🏝 かきくけこ うえお あい
����㏁㍁㋁
🏝 かきくけこ うえお あい 
🏝こけくきかおえういあ
Perlの文字列はディフォルトではバイトシーケンスなのでバイト逆順にすると多バイト文字は破綻し、上記のように文字化けします。
use utf8;で、バイトシーケンスから内部エンコーディング( Wide character )に切替えることができますが、このまま say すると内部エンコーディングのままなので、標準出力のレイヤーを ":encoding(UTF-8)" に変更します。

sprintf

編集
書式
sprintf FORMAT, LIST</syntaxhighlight copy>
:LIST  FORMAT に従って整形して返します
==== tr ====
;書式:<syntaxhighlight lang=perl>tr///</syntaxhighlight copy>
:1文字を対応する1文字に置換します詳細は[[Perl/演算子|演算子]]の章を参照
==== y ====
;書式:<syntaxhighlight lang=perl>y///</syntaxhighlight copy>
:tr///と同義

=== 正規表現とパターンマッチ ===

Perlにはテキスト処理やパターンマッチングに役立つ様々な機能が備わっています
以下ではそれぞれの機能について解説します

; m// 演算子
: パターンマッチング演算子として知られており文字列内でパターンを検索するために使用されます正規表現を使ってパターンを指定しマッチした部分を取得したりマッチングの成否を確認したりすることができます例えば次のように使用します
:<syntaxhighlight lang=perl copy>
my $str = "Hello World";
if ($str =~ m/World/) {
    print "マッチしました\n";
}
pos 関数
pos 関数は、直近のパターンマッチングでマッチした部分文字列の次の検索位置を示します。次のパターンマッチングでの開始位置を変更するために使用されます。例えば、次のように使用します。
my $str = "abcabc";
while ($str =~ m/abc/g) {
    print "マッチ位置: " . pos($str) . "\n";
}
qr// 演算子
qr// 演算子は、正規表現を表すオブジェクトを生成します。これは、後で同じ正規表現を再利用する場合に便利です。例えば、次のように使用します。
my $pattern = qr/abc/;
if ($str =~ $pattern) {
    print "マッチしました\n";
}
quotemeta 関数
quotemeta 関数は、文字列内のメタ文字をエスケープします。これにより、文字列をそのままパターンとして使用する際に、意図しない動作を防ぐことができます。例えば、次のように使用します。
my $str = "a+";
my $pattern = quotemeta($str);
if ($input =~ m/$pattern/) {
    print "マッチしました\n";
}
s/// 演算子
置換演算子として知られており、文字列内のパターンにマッチする部分を置換します。例えば、次のように使用します。
my $str = "apple orange";
$str =~ s/apple/banana/;
print $str;  # "banana orange" を出力
split 関数
split 関数は、文字列を指定した区切り文字で分割し、リストに格納します。例えば、次のように使用します。
my $str = "apple,orange,banana";
my @fruits = split /,/, $str;
print join("-", @fruits);  # "apple-orange-banana" を出力
study 関数
study 関数は、文字列内のパターンマッチングを高速化するための最適化を行います。特に大きな文字列を検索する場合に有効です。例えば、次のように使用します。
my $str = "very long string...";
study $str;
if ($str =~ m/pattern/) {
    print "マッチしました\n";
}

これらの機能を使用することで、Perlでのテキスト処理やパターンマッチングを効率的に行うことができます。

数値演算関数

編集
abs, atan2, cos, exp, hex, int, log, oct, rand, sin, sqrt, srand

これらの関数はPerlで数学的な操作を行うための組み込み関数です。以下にそれぞれの関数を簡単に説明します。

abs
数値の絶対値を返します。
my $num = -10;
my $abs_num = abs($num);  # $abs_num には 10 が格納されます
atan2
y/x のアークタンジェントを返します。y と x を引数に取ります。
my $atan_value = atan2($y, $x);
cos
弧度法で与えられた角度の余弦を返します。
my $cos_value = cos($angle);
exp
指数関数   を返します。
my $exp_value = exp($x);
hex
文字列を 16 進数として解釈し、整数値を返します。
my $hex_value = hex("0xFF");  # $hex_value には 255 が格納されます
int
数値の整数部分を返します。
my $num = 3.6;
my $int_num = int($num);  # $int_num には 3 が格納されます
log
自然対数を返します。
my $log_value = log($x);
oct
文字列を 8 進数として解釈し、整数値を返します。
my $oct_value = oct("077");  # $oct_value には 63 が格納されます
rand
0 から 1 未満の乱数を返します。
my $rand_value = rand();
sin
弧度法で与えられた角度の正弦を返します。
my $sin_value = sin($angle);
sqrt
数値の平方根を返します。
my $sqrt_value = sqrt($num);
srand
乱数のシードを設定します。これにより、乱数生成のシーケンスが初期化されます。
srand(time);  # 現在時刻をシードとして使用する例

これらの関数を使用することで、Perlでの数学的な操作を簡単に行うことができます。

配列操作

編集
each, keys, pop, push, shift, splice, unshift, values

これらの関数は、Perlで配列を操作するための組み込み関数です。以下にそれぞれの関数を説明します。

each
配列を反復処理するために使用されます。各反復で、配列内の次の要素を返します。
my @array = ('a', 'b', 'c');
while (my ($index, $value) = each @array) {
    print "Index: $index, Value: $value\n";
}
keys
配列のインデックス(キー)を取得します。通常、数値のインデックスが返されます。
my @array = ('a', 'b', 'c');
my @indices = keys @array;  # @indices には (0, 1, 2) が格納されます
pop
配列の末尾から要素を取り出します(削除)。
my @array = (1, 2, 3, 4, 5);
my $last_element = pop @array;  # $last_element には 5 が格納され、@array は (1, 2, 3, 4) になります
push
配列の末尾に要素を追加します。
my @array = (1, 2, 3);
push @array, 4, 5;  # @array は (1, 2, 3, 4, 5) になります
shift
配列の先頭から要素を取り出します(削除)。
my @array = (1, 2, 3, 4, 5);
my $first_element = shift @array;  # $first_element には 1 が格納され、@array は (2, 3, 4, 5) になります
splice
配列の指定した範囲の要素を置換または削除し、新しい要素を挿入します。
my @array = (1, 2, 3, 4, 5);
splice @array, 2, 2, 'a', 'b';  # @array は (1, 2, 'a', 'b', 5) になります
unshift
配列の先頭に要素を追加します。
my @array = (3, 4, 5);
unshift @array, 1, 2;  # @array は (1, 2, 3, 4, 5) になります

これらの関数を使用することで、Perlで配列を効果的に操作することができます。

リスト操作

編集
grep, join, map, qw//, reverse, sort, unpack

Perlにおけるリスト操作に関する関数や演算子について解説します。

grep
リスト内の要素をフィルタリングします。条件にマッチする要素だけを残した新しいリストを返します。
my @numbers = (1, 2, 3, 4, 5);
my @even_numbers = grep { $_ % 2 == 0 } @numbers;  # @even_numbers には (2, 4) が格納されます
join
リストの要素を指定した区切り文字で結合して文字列を生成します。
my @words = ('hello', 'world', '!');
my $sentence = join ' ', @words;  # $sentence には "hello world !" が格納されます
map
リストの各要素に対して処理を行い、結果を新しいリストとして返します。
my @numbers = (1, 2, 3);
my @squared_numbers = map { $_ ** 2 } @numbers;  # @squared_numbers には (1, 4, 9) が格納されます
qw//
クォートワード演算子。文字列をスペースで区切り、リストとして返します。
my @words = qw(apple banana orange);  # @words には ('apple', 'banana', 'orange') が格納されます
reverse
リストの要素の順序を逆にします。
my @numbers = (1, 2, 3);
my @reversed_numbers = reverse @numbers;  # @reversed_numbers には (3, 2, 1) が格納されます
sort
リストの要素をソートします。デフォルトでは文字列としてソートされますが、数値としてソートしたい場合は sort {$a <=> $b} のようにコードブロックを指定します。
my @numbers = (3, 1, 2);
my @sorted_numbers = sort @numbers;  # @sorted_numbers には (1, 2, 3) が格納されます
unpack
文字列を指定したテンプレートに従って解釈し、リストとして返します。主にバイナリデータの処理に使用されます。
my $binary_data = "\x41\x42\x43";
my @values = unpack 'C*', $binary_data;  # @values には (65, 66, 67) が格納されます

これらの関数や演算子を使うことで、Perlでリストを効果的に操作することができます。

ハッシュ操作

編集
delete, each, exists, keys, values

Perlにおけるハッシュ(連想配列)の操作について説明します。

delete
ハッシュから指定したキーとその関連する値を削除します。
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
delete $hash{'b'};  # ハッシュから 'b' キーとその値を削除します
each
ハッシュを反復処理するために使用されます。各反復で、キーと値のペアを返します。
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
while (my ($key, $value) = each %hash) {
    print "$key: $value\n";
}
exists
指定したキーがハッシュ内に存在するかどうかを確認します。存在する場合は真を返し、存在しない場合は偽を返します。
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
if (exists $hash{'b'}) {
    print "'b' キーは存在します\n";
} else {
    print "'b' キーは存在しません\n";
}
keys
ハッシュのキーのリストを取得します。
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @keys = keys %hash;  # @keys には ('a', 'b', 'c') が格納されます
values
ハッシュの値のリストを取得します。
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @values = values %hash;  # @values には (1, 2, 3) が格納されます

これらの関数や演算子を使うことで、Perlでハッシュを効果的に操作することができます。

binmode, close, closedir, dbmclose, dbmopen, die, eof, fileno, flock, format, getc, print, printf, read, readdir, readline, rewinddir, say, seek, seekdir, select, syscall, sysread, sysseek, syswrite, tell, telldir, truncate, warn, write


固定長データとレコード

編集
pack, read, syscall, sysread, sysseek, syswrite, unpack, vec

ファイルハンドル・ファイルとディレクトリ

編集
-X, chdir, chmod, chown, chroot, fcntl, glob, ioctl, link, lstat, mkdir, open, opendir, readlink, rename, rmdir, select, stat, symlink, sysopen, umask, unlink, utime

制御構造

編集
break, caller, continue, die, do, dump, eval, evalbytes, exit, __FILE__, goto, last, __LINE__, next, __PACKAGE__, redo, return, sub, __SUB__, wantarray

スコープ

編集
caller, import, local, my, our, package, state, use
defined, formline, lock, prototype, reset, scalar, undef

プロセス

編集
alarm, exec, fork, getpgrp, getppid, getpriority, kill, pipe, qx//, readpipe, setpgrp, setpriority, sleep, system, times, wait, waitpid

モジュール

編集
do, import, no, package, require, use

オブジェクト指向

編集
bless, dbmclose, dbmopen, package, ref, tie, tied, untie, use

Socket

編集
accept, bind, connect, getpeername, getsockname, getsockopt, listen, recv, send, setsockopt, shutdown, socket, socketpair

System V IPC

編集
msgctl, msgget, msgrcv, msgsnd, semctl, semget, semop, shmctl, shmget, shmread, shmwrite

ユーザーとグループ

編集
endgrent, endhostent, endnetent, endpwent, getgrent, getgrgid, getgrnam, getlogin, getpwent, getpwnam, getpwuid, setgrent, setpwent

ネットワーク情報

編集
endprotoent, endservent, gethostbyaddr, gethostbyname, gethostent, getnetbyaddr, getnetbyname, getnetent, getprotobyname, getprotobynumber, getprotoent, getservbyname, getservbyport, getservent, sethostent, setnetent, setprotoent, setservent

日付時刻

編集
gmtime, localtime, time, times

関数以外のキーワード

編集
and, AUTOLOAD, BEGIN, catch, CHECK, cmp, CORE, __DATA__, default, defer, DESTROY, else, elseif, elsif, END, __END__, eq, finally, for, foreach, ge, given, gt, if, INIT, isa, le, lt, ne, not, or, try, UNITCHECK, unless, until, when, while, x, xor


組込み関数一覧

編集

each keys pop push shift splice unshift values

retrieve the next key/value pair from a hash

retrieve list of indices from a hash

remove the last element from an array and return it

append one or more elements to an array

remove the first element of an array, and return it

splice

編集

add or remove elements anywhere in an array

unshift

編集

prepend more elements to the beginning of a list

values

編集

return a list of the values in a hash

Binary

編集

pack read syscall sysread sysseek syswrite unpack vec

convert a list into a binary representation

fixed-length buffered input from a filehandle

syscall

編集

execute an arbitrary system call

sysread

編集

fixed-length unbuffered input from a filehandle

sysseek

編集

position I/O pointer on handle used with sysread and syswrite

syswrite

編集

fixed-length unbuffered output to a filehandle

unpack

編集

Perlのunpack関数は、指定されたフォーマットに従ってバイナリ文字列をアンパックしてデータを取得します。主にバイナリデータを処理する際に使用されます。以下は、unpack関数の基本的な使用例と一般的なフォーマット指定子の一部です。

# バイナリ文字列を作成する例
my $binary_data = "ABCDHello";

# バイナリ文字列をアンパックしてデータを取得する
my ($num1, $num2, $string) = unpack('C4 A4', $binary_data);

print "$num1 $num2 $string\n";  #=> 65 66 67

一般的なフォーマット指定子の一部は以下の通りです。

  • A - 文字列
  • C - 符号なし8ビット整数 (1 バイト)
  • S - 符号なし16ビット整数 (2 バイト)
  • L - 符号なし32ビット整数 (4 バイト)
  • n - ネットワークバイトオーダー (big-endian) の16ビット整数
  • N - ネットワークバイトオーダーの32ビット整数
  • v - リトルエンディアンバイトオーダーの16ビット整数
  • V - リトルエンディアンバイトオーダーの32ビット整数

unpack関数は、バイナリデータを他の形式に変換する際に非常に便利です。

test or set particular bits in a string

-X chdir chmod chown chroot fcntl glob ioctl link lstat mkdir open opendir readlink rename rmdir select stat symlink sysopen umask unlink utime

a file test (-r, -x, etc)

change your current working directory

changes the permissions on a list of files

change the ownership on a list of files

chroot

編集

make directory new root for path lookups

file control system call

expand filenames using wildcards

system-dependent device control system call

create a hard link in the filesystem

stat a symbolic link

create a directory

open a file, pipe, or descriptor

opendir

編集

open a directory

編集

determine where a symbolic link is pointing

rename

編集

change a filename

remove a directory

select

編集

reset default output or do I/O multiplexing

get a file's status information

編集

create a symbolic link to a file

sysopen

編集

open a file, pipe, or descriptor

set file creation mode mask

編集

remove one link to a file

set a file's last access and modify times

break caller continue die do dump eval evalbytes exit __FILE__ goto last __LINE__ next __PACKAGE__ redo return sub __SUB__ wantarray

break out of a C<given> block

caller

編集

get context of the current subroutine call

continue

編集

optional trailing block in a while or foreach

raise an exception or bail out

turn a BLOCK into a TERM

create an immediate core dump

catch exceptions or compile and run code

evalbytes

編集

similar to string eval, but intend to parse a bytestream

terminate this program

__FILE__

編集

the name of the current source file

create spaghetti code

exit a block prematurely

__LINE__

編集

the current source line number

iterate a block prematurely

__PACKAGE__

編集

the current package

start this loop iteration over again

return

編集

get out of a function early

declare a subroutine, possibly anonymously

__SUB__

編集

the current subroutine, or C<undef> if not in a subroutine

wantarray

編集

get void vs scalar vs list context of current subroutine call

delete each exists keys values

delete

編集

deletes a value from a hash

retrieve the next key/value pair from a hash

exists

編集

test whether a hash key is present

retrieve list of indices from a hash

values

編集

return a list of the values in a hash

binmode close closedir dbmclose dbmopen die eof fileno flock format getc print printf read readdir readline rewinddir say seek seekdir select syscall sysread sysseek syswrite tell telldir truncate warn write

binmode

編集

prepare binary files for I/O

close file (or pipe or socket) handle

closedir

編集

close directory handle

dbmclose

編集

breaks binding on a tied dbm file

dbmopen

編集

create binding on a tied dbm file

raise an exception or bail out

test a filehandle for its end

fileno

編集

return file descriptor from filehandle

lock an entire file with an advisory lock

format

編集

declare a picture format with use by the write() function

get the next character from the filehandle

output a list to a filehandle

printf

編集

output a formatted list to a filehandle

fixed-length buffered input from a filehandle

readdir

編集

get a directory from a directory handle

readline

編集

fetch a record from a file

rewinddir

編集

reset directory handle

output a list to a filehandle, appending a newline

reposition file pointer for random-access I/O

seekdir

編集

reposition directory pointer

select

編集

reset default output or do I/O multiplexing

syscall

編集

execute an arbitrary system call

sysread

編集

fixed-length unbuffered input from a filehandle

sysseek

編集

position I/O pointer on handle used with sysread and syswrite

syswrite

編集

fixed-length unbuffered output to a filehandle

get current seekpointer on a filehandle

telldir

編集

get current seekpointer on a directory handle

truncate

編集

shorten a file

print debugging info

print a picture record

grep join map qw/STRING/ reverse sort unpack

locate elements in a list test true against a given criterion

join a list into a string using a separator

apply a change to a list to get back a new list with the changes

qw/STRING/

編集

quote a list of words

reverse

編集

flip a string or a list

sort a list of values

unpack

編集

convert binary structure into normal perl variables

abs atan2 cos exp hex int log oct rand sin sqrt srand

absolute value function

arctangent of Y/X in the range -PI to PI

cosine function

raise I<e> to a power

convert a hexadecimal string to a number

get the integer portion of a number

retrieve the natural logarithm for a number

convert a string to an octal number

retrieve the next pseudorandom number

return the sine of a number

square root function

seed the random number generator

defined formline lock prototype reset scalar undef

defined

編集

test whether a value, variable, or function is defined

formline

編集

internal function used for formats

get a thread lock on a variable, subroutine, or method

prototype

編集

get the prototype (if any) of a subroutine

clear all variables of a given name

scalar

編集

force a scalar context

remove a variable or function definition

Modules

編集

do import no package require use

turn a BLOCK into a TERM

import

編集

patch a module's namespace into your own

unimport some module symbols or semantics at compile time

package

編集

declare a separate global namespace

require

編集

load in external functions from a library at runtime

load in a module at compile time and import its namespace

Namespace

編集

caller import local my our package state use

caller

編集

get context of the current subroutine call

import

編集

patch a module's namespace into your own

create a temporary value for a global variable (dynamic scoping)

declare and assign a local variable (lexical scoping)

declare and assign a package variable (lexical scoping)

package

編集

declare a separate global namespace

declare and assign a persistent lexical variable

load in a module at compile time and import its namespace

Network

編集

endprotoent endservent gethostbyaddr gethostbyname gethostent getnetbyaddr getnetbyname getnetent getprotobyname getprotobynumber getprotoent getservbyname getservbyport getservent sethostent setnetent setprotoent setservent

endprotoent

編集

be done using protocols file

endservent

編集

be done using services file

gethostbyaddr

編集

get host record given its address

gethostbyname

編集

get host record given name

gethostent

編集

get next hosts record

getnetbyaddr

編集

get network record given its address

getnetbyname

編集

get networks record given name

getnetent

編集

get next networks record

getprotobyname

編集

get protocol record given name

getprotobynumber

編集

get protocol record numeric protocol

getprotoent

編集

get next protocols record

getservbyname

編集

get services record given its name

getservbyport

編集

get services record given numeric port

getservent

編集

get next services record

sethostent

編集

prepare hosts file for use

setnetent

編集

prepare networks file for use

setprotoent

編集

prepare protocols file for use

setservent

編集

prepare services file for use

Objects

編集

bless dbmclose dbmopen package ref tie tied untie use

create an object

dbmclose

編集

breaks binding on a tied dbm file

dbmopen

編集

create binding on a tied dbm file

package

編集

declare a separate global namespace

find out the type of thing being referenced

bind a variable to an object class

get a reference to the object underlying a tied variable

break a tie binding to a variable

load in a module at compile time and import its namespace

Process

編集

alarm exec fork getpgrp getppid getpriority kill pipe qx/STRING/ readpipe setpgrp setpriority sleep system times wait waitpid

schedule a SIGALRM

abandon this program to run another

create a new process just like this one

getpgrp

編集

get process group

getppid

編集

get parent process ID

getpriority

編集

get current nice value

send a signal to a process or process group

open a pair of connected filehandles

qx/STRING/

編集

backquote quote a string

readpipe

編集

execute a system command and collect standard output

setpgrp

編集

set the process group of a process

setpriority

編集

set a process's nice value

block for some number of seconds

system

編集

run a separate program

return elapsed time for self and child processes

wait for any child process to die

waitpid

編集

wait for a particular child process to die

Regexp

編集

m// pos qr/STRING/ quotemeta s/// split study

match a string with a regular expression pattern

find or set the offset for the last/next m//g search

qr/STRING/

編集

compile pattern

quotemeta

編集

quote regular expression magic characters

replace a pattern with a string

split up a string using a regexp delimiter

no-op, formerly optimized input data for repeated searches

Socket

編集

accept bind connect getpeername getsockname getsockopt listen recv send setsockopt shutdown socket socketpair

accept

編集

accept an incoming socket connect

binds an address to a socket

connect

編集

connect to a remote socket

getpeername

編集

find the other end of a socket connection

getsockname

編集

retrieve the sockaddr for a given socket

getsockopt

編集

get socket options on a given socket

listen

編集

register your socket as a server

receive a message over a Socket

send a message over a socket

setsockopt

編集

set some socket options

shutdown

編集

close down just half of a socket connection

socket

編集

create a socket

socketpair

編集

create a pair of sockets

String

編集

chomp chop chr crypt fc hex index lc lcfirst length oct ord pack q/STRING/ qq/STRING/ reverse rindex sprintf substr tr/// uc ucfirst y///

remove a trailing record separator from a string

remove the last character from a string

get character this number represents

one-way passwd-style encryption

return casefolded version of a string

convert a hexadecimal string to a number

find a substring within a string

return lower-case version of a string

lcfirst

編集

return a string with just the next letter in lower case

length

編集

return the number of characters in a string

convert a string to an octal number

find a character's numeric representation

convert a list into a binary representation

q/STRING/

編集

singly quote a string

qq/STRING/

編集

doubly quote a string

reverse

編集

flip a string or a list

rindex

編集

right-to-left substring search

sprintf

編集

formatted print into a string

substr

編集

get or alter a portion of a string

transliterate a string

return upper-case version of a string

ucfirst

編集

return a string with just the next letter in upper case

transliterate a string

msgctl msgget msgrcv msgsnd semctl semget semop shmctl shmget shmread shmwrite

msgctl

編集

SysV IPC message control operations

msgget

編集

get SysV IPC message queue

msgrcv

編集

receive a SysV IPC message from a message queue

msgsnd

編集

send a SysV IPC message to a message queue

semctl

編集

SysV semaphore control operations

semget

編集

get set of SysV semaphores

SysV semaphore operations

shmctl

編集

SysV shared memory operations

shmget

編集

get SysV shared memory segment identifier

shmread

編集

read SysV shared memory

shmwrite

編集

write SysV shared memory

gmtime localtime time times

gmtime

編集

convert UNIX time into record or string using Greenwich time

localtime

編集

convert UNIX time into record or string using local time

return number of seconds since 1970

return elapsed time for self and child processes

endgrent endhostent endnetent endpwent getgrent getgrgid getgrnam getlogin getpwent getpwnam getpwuid setgrent setpwent

endgrent

編集

be done using group file

endhostent

編集

be done using hosts file

endnetent

編集

be done using networks file

endpwent

編集

be done using passwd file

getgrent

編集

get next group record

getgrgid

編集

get group record given group user ID

getgrnam

編集

get group record given group name

getlogin

編集

return who logged in at this tty

getpwent

編集

get next passwd record

getpwnam

編集

get passwd record given user login name

getpwuid

編集

get passwd record given user ID

setgrent

編集

prepare group file for use

setpwent

編集

prepare passwd file for use