Perl/統合版
本書は、Perlのチュートリアルです。 Perlは、Practical Extraction and Report Languageの略で、実用的な抽出・報告言語です。 1987年にUNIXの世界に出現したこの言語は、ラリー・ウォールという一人の人間の手によるもので、今日に至るまでPerlの文法改良をリードし続けています。
Perlの重要な点は、スクリプト言語であるため、プログラムのソースコードを無償で提供することです。このため、例題を通してPerlを簡単に学ぶことができ、また、何千ものスクリプトをダウンロードして、自分用に修正することも可能です。
Perlは、非常にわかりやすく、広く知られているプログラム記述言語です。DOSのバッチファイルやシェルスクリプトに相当するものを作成するなど、さまざまな作業に使われますが、Web開発の文脈では、CGIスクリプトを開発するために使用されます。
しかし、Perlのフリーコードの多くは理解不可能で、全く謎めいたスタイルをしていることが、Perlの悪いところです。
Perlは、非常に強力な言語ですが、その反面、習得が難しい言語でもあります。しかし、Perlを習得すれば、さまざまなことができるようになります。
はじめに[編集]
TMTOWTDI[編集]
Perl(パール)とは、1987年にラリー・ウォールが開発したプログラミング言語です。PerlはC言語をはじめ、AWKやsedのような様々なUNIXのソフトウェアの伝統を受け継ぎ、多くの優れた機能を取り入れています。
PerlのモットーはThere's More Than One Way To Do It.(やり方は何通りもある)で、略してTMTOWTDI(ティムトゥディ)などと呼ばれます。これは「正しいやり方がいくつ存在してもよい」という考え方で、Perlの柔軟性を表しています。このことから、Perlは特にテキスト処理やCGIプログラミングの分野で多く用いられています。
PerlはC言語と比べて簡潔であり、移植性が高い言語です。C言語では数百行のプログラムが必要な場合でも、Perlでは数行で書くことができることもあります。
一方で、Perlの文法は省略を多用したり、特殊変数を記号で表すことがありますので、Perlのやり方に慣れるまでには少し時間がかかるかもしれません。しかし、一行でも多くのコードを書いてPerlを身につけることをお勧めします。
前提条件[編集]
テキストエディタを用いて例に挙げられる通りのファイルを作成できることを前提としています。プログラミングそのものの概念についてはプログラミング(Wikibooks)やプログラミング(Wikipedia)を参照してください。以降、断りのない場合はUnix(およびLinuxなどのUnix互換OS)上で Perl 5.30.0(2019年05月22日 リリース)以降のバージョンを利用しているものとして説明します(かつて Perl6 と呼ばれていた Raku は含みません)。
実行環境[編集]
Microsoft Windows[編集]
Perl公式サイトではWindowsに対応したパッケージは提供していません。 このため、サードパーティーが提供するPerlのディストリビューションを利用するか、CygwinやWindows Subsystem for Linuxを利用する方法もあります。
ActivePerl[編集]
ActivePerlは、ActiveState社(旧ソフォス社)が提供するWindows、Linux、macOS向けのPerlのディストリビューションです。
- 2023年10月現在、ActivePerlのPerlコアはv5.36(2022/05/28リリース)です。
- Download & Install Perl - ActiveState
Strawberry Perl[編集]
Strawberry Perlは、Microsoft Windowsプラットフォーム用のプログラミング言語Perlのディストリビューションです。 Strawberry Perlには、完全に機能するMingw-w64 C/C++コンパイラなどのツールチェインが含まれています。 Strawberry Perlは、環境変数はインストール時に設定済みなので、インストール直後に、コマンド プロンプト・Power shellあるいは、Windows Terminalから使うことができます。
- 2022年11月現在、Strawberry PerlのPerlコアはv5.32.1(2021/01/24リリース)です。
- Strawberry Perl for Windows
macOS, FreeBSD, その他 UNIX 環境[編集]
maxOS, FreeBSD, その他 UNIX 環境ではほとんどの場合、PerlはOSのユーザーランドとは別にパッケージとして提供されています。「ターミナル」を起動し、コマンドプロンプト($, %, >などの記号)に続けてperl -vと入力し、⏎([Enter]または[Return])キーを押し、以下のように表示されればperlが利用可能です。
% perl -v This is perl 5, version 38, subversion 0 (v5.38.0) built for x86_64-linux Copyright 1987-2023, Larry Wall Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet, point your browser at https://www.perl.org/, the Perl Home Page. % _
PerlがインストールされていないUNIX環境[編集]
主要なUNIXならは、Perlをサポートしていると思いますが、もしOSの公式パッケージにperlが無い場合でも、 Perl Download - www.perl.orgからバイナリパッケージをダウンロードできます。
バイナリパッケージが存在しないプラットフォームの場合はPerl Download - www.perl.orgからソースコードをダウンロードし、ビルドして実行してください。
GNU/Linux[編集]
GNU/Linux の場合、Linux Standard Base(LSB; ISO/IEC 23360:2021)では、準拠するすべてのディストリビューションにPerlをインストールして出荷することが義務付けられています[1]。 しかし、何らかの理由でインストールされていないディストリビューションでは、apt などのパッケージマネージャーを利用してインストールする必要があります。 詳細は、利用しているディストリビューションのパッケージマネージャーの利用法を確認してください。 また、既に Perl がインストールされている環境でも、最新のバージョンを維持するためにパッケージマネージャーを利用して update するよう心がけ、脆弱性があるまま使わないようにしましょう。
作成、実行の流れ[編集]
プログラムの作成[編集]
Perlはインタプリター言語です。つまり、プログラムを実行するたびに、コンパイル[2]と実行を行うPerlインタプリターが常に必要なのです。 C/C++やJavaのようにプログラムをコンパイルしてから実行するのではなく、プログラムのソースコードを(Perlインタプリターがある)別のコンピューターにコピーして実行するだけで良いのです。
ソースコードの編集には好きなテキストエディタを使うことができます。 OS標準のメモ帳(Windows)、TextEdit(macOS)、vi(UnixやUnix互換OS)などでも十分です。 Wordなどのワードプロセッサーでも編集は可能ですが、標準ではプレーンテキストとして保存されないので注意してください。
Perlで書かれたコードを実行したい場合には、テキストエディタで実行したいコードを書いてセーブ保存してから、コマンド端末から保存したファイルを perl で実行することになります。
デバッガー[編集]
Perlにも、Pythonの対話モードのような REPL( Read-Eval-Print Loop ) があります。
- デバッガーの起動例
% perl -de 1 Loading DB routines from perl5db.pl version 1.77 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(-e:1): 1 DB<1> say 2**9 512 DB<2> say "Hello world!" Hello world! DB<3> q % _
- 短いコードの確認には、このデバッグモードが便利です。
プログラムの実行[編集]
テキストエディタでhello.pl
というソースファイルを下記のように作成し、
- hello.pl
#!/usr/bin/env perl use v5.30.0; say "Hello, World"; say "Hello, Perl";
- コマンドラインでの実行
% cat > hello.pl #!/usr/bin/env perl use v5.30.0; say "Hello, World"; say "Hello, Perl"; ^D % perl hello.pl Hello, World Hello, Perl % chmod +x hello.pl % ./hello.pl Hello, World Hello, Perl % _
- say は、文字列または文字列のリストを表示(して改行)する組込み関数です。
- Perlの文字列リテラルは、
"
(ダブルクォーテーションマーク)で囲みます。 ’
(シングルクオーテーション)で囲んで文字列リテラルを表現できますが、この場合は改行文字(\n
)などのバックスラッシュエスケープや変数($x
,@y
や%z
,)が展開されずそのまま表示されるなどの違いがあります。
Perlは、多くのプログラミング言語と同様に、Perlは構造化プログラミングというプログラミングパラダイムを採用しています。 プログラムの流れは逐次・分岐・反復の3つが基本です[3]。 つまり、原則としてプログラムはソースコードに記述された順に実行され、if や for などの制御構造があったときだけ分岐・反復します。
Perlの基本機能の紹介[編集]
変数の宣言と初期化[編集]
Perlでは、変数は「データを格納する領域(オブジェクト)に付けられた名前」です(動的型付け)。 Perlでは変数名(例ではx)の前に$, %, @などの接頭辞(sigil; シジル)がつく表現を変数として扱います。
- コード例(エラーとなります)
#!/usr/bin/env perl use v5.12; #use strict; v5.12以降は use strict を含んでいるので以後は略します use warnings; $x = "Perl"; say "Hello, $x";
- 実行結果
Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at Main.pl line 6. Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at Main.pl line 7. Execution of Main.pl aborted due to compilation errors.
- シバン(shebang!)で、スクリプトを実行するインタープリターの位置を教えます。
#!/usr/bin/perl
とする例を見かけますが、perl が /usr/bin/perl でなく他の場所(例えば /usr/local/bin/perl)にインストールされている可能性があるので#!/usr/bin/env perl
としました。これは、PATHが通ったディレクトリに perl と言う名前のトロージャンホースを仕掛けられるリスクがあるとの批判がありますが、$ perl hello.pl
するときにも同じリスクがあり、リスクゼロではありませんが受入れがたいものではないと考えられます。
- Perl v5.12 以降の機能を有効にしています。
- 安全ではない構文を制限する Perl プラグマ strict は Perl5.12 からディフォルトで有効です[4]。
- strict が有効なので、グローバル変数の使用はエラーとなります。
- 無効にするのは、 no strict; とします。
- 選択的な警告を調整する Perl warnings です[5]。
- これは、Perl5.36.0 以降でディフォルトで有効なので 5.36 より前のスクリプトでは、明示的に use warnings; が必要です。
この対策として、キーワード my
を使ってレキシカルスコープの変数(レキシカル変数)として宣言します。
- コード例(修正後)
#!/usr/bin/env perl use v5.12; # use strict; use warnings; my $x = "Perl"; say "Hello, $x";
- 実行結果
Hello, Perl
- 6行目を修正した結果、正しく実行できました。
- この様にに、
use v5.12;
以降を指定することで、 安全でないコードを早い段階で発見できます。
Perlでは例にあるような構造のない、ただ一つの値のみを保有するデータ(スカラーと呼びます)のほか、順番に並んだ複数のデータからなる配列、キーと値のペアー複数記録するハッシュ、より複雑なデータ構造を実現するリファレンスなどのデータを扱うことができます。 変数についての詳細は変数とデーター型で解説します。 リファレンスについての詳細はリファレンスで解説します。
式と演算子[編集]
Perlには、豊富な数値計算のための演算子が用意されており、それらを組み合わせて式を作ることが出来ます。
- コード例
#!/usr/bin/env perl use v5.12; use warnings; say 12 + 5; say 12 - 5; say 12 * 5; say 12 / 5; say 12 % 5; say 12 ** 5; say 12 & 5; say 12 | 5; say 12 ^ 5; say 12 << 1; say 12 >> 1; say -12; say +12;
- 実行結果
17 7 60 2.4 2 248832 4 13 9 24 6 -12 12
- 四則 徐 剰余 累乗 ビット間論理積 ビット間論理和 ビット間排他的論理和 右シフト 左シフト 単項マイナス 単項プラス です
use v5.12;とuse warnings; |
プラグマ use v5.12;とuse warnings;は必ずプログラム冒頭で指定しましょう。
use v5.12;のv5.12は、自分の使っているPERLインタープリターのバージョン(特殊変数 $^V で確認できます)で良いでしょう。 もし、指定しないと組込み関数のスペルミス程度でも、エラーも警告もなく思いもかけない結果になります。
|
- コード例
use v5.12; use warnings; $x = cyop; print $x
- 実行時エラー
Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at Main.pl line 4. Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at Main.pl line 5. Bareword "cyop" not allowed while "strict subs" in use at Main.pl line 4. Execution of Main.pl aborted due to compilation errors.
制御構造[編集]
原則としてPerlのプログラムは上に書かれているものから順に実行されていきますが、繰り返しや、特定の条件に応じて動作を切り替えることができます。
条件分岐[編集]
ある条件をみたしているか(ここでは$x が 3 より大きいかどうか)を判定し、判定の内容により動作を切り替えています。
- コード例
#!/usr/bin/env perl use v5.12; use warnings; my $x = 5; if ($x > 3){ say "$x > 3" } else { say "$x <= 3" }
- 実行結果
5 > 3
反復[編集]
反復は、あるブロックを繰り返す制御構造でループとも呼ばれます。
- コード例
#!/usr/bin/env perl use v5.12; use warnings; foreach my $num (1 .. 10) { print "$num "; } say ""
- 実行結果
1 2 3 4 5 6 7 8 9 10
コメント[編集]
プログラミングの作成中に「プログラム内にメモを残しておきたい」「一時的にある動作を実行されないようにしたい」といった要求が生じることがあります。このような「プログラミングのコードに記載されるが動作しない箇所」のことを一般にコメントと呼びます。
- コード例
#!/usr/bin/env perl use v5.12; use warnings; # シャープ以降から行末まで実行されない say "ここはコメントの外";
- 実行結果
ここはコメントの外
- Perlでは#以降の行端までがコメントとみなされます。C言語にあるような複数行にわたるコメントはありませんが、以下のような方法で実質的な複数行コメントを利用することができます。
Podによるドキュメンテーション[編集]
PerlのPodは、Plain Old Documentationの略で、Perlスクリプトのドキュメンテーションを書くためのフォーマットです。 Podは、テキストファイルに記述され、スクリプトと一緒に配布されることが一般的です。 Podは、人間が読みやすいドキュメントを作成するために設計されていますが、コンピュータプログラムにも解析可能な単純な構文があります。
以下はPerlで1から100の間の素数をすべて表示するプログラムにPodによるドキュメントも付加した例です。
#!/usr/bin/env perl use v5.12; use warnings; =head1 NAME find_primes.pl - Find all prime numbers between 1 and 100 =head1 SYNOPSIS perl find_primes.pl =head1 DESCRIPTION This program finds all prime numbers between 1 and 100 and prints them to the console. =head1 AUTHOR Your Name =cut # Initialize an array to hold the prime numbers my @primes = (); # Loop through all numbers between 1 and 100 for my $num (1..100) { my $is_prime = 1; # Check if the number is divisible by any number other than itself and 1 for my $divisor (2..int($num/2)) { if ($num % $divisor == 0) { $is_prime = 0; last; } } # If the number is prime, add it to the array push @primes, $num if $is_prime; } # Print the prime numbers to the console print "Prime numbers between 1 and 100:\n"; print join(", ", @primes) . "\n";
- HTMLのレンダリング例
<?xml version="1.0" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>find_primes.pl - Find all prime numbers between 1 and 100</title> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <link rev="made" href="mailto:mat@FreeBSD.org" /> </head> <body> <ul id="index"> <li><a href="#NAME">NAME</a></li> <li><a href="#SYNOPSIS">SYNOPSIS</a></li> <li><a href="#DESCRIPTION">DESCRIPTION</a></li> <li><a href="#AUTHOR">AUTHOR</a></li> </ul> <h1 id="NAME">NAME</h1> <p>find_primes.pl - Find all prime numbers between 1 and 100</p> <h1 id="SYNOPSIS">SYNOPSIS</h1> <pre><code>perl find_primes.pl</code></pre> <h1 id="DESCRIPTION">DESCRIPTION</h1> <p> This program finds all prime numbers between 1 and 100 and prints them to the console. </p> <h1 id="AUTHOR">AUTHOR</h1> <p>Your Name</p> </body> </html>
上記の例では、=head1
はセクションの見出しを表します。
NAME
とSYNOPSIS
は、モジュールの名前と使用例を説明します。
DESCRIPTION
は、モジュールの機能の詳細な説明であり、AUTHOR
は、モジュールの作者の情報を提供します。
脚註[編集]
- ^
/usr/bin/perl
にPerlインタープリターも実行形式または実行形式へのリンクが有り ⇒ Linux Standard Base Languages Specification 5.0::7.2. Perl Interpreter Location、v5.8.8 以降であることが義務付けられています ⇒Linux Standard Base Languages Specification 5.0::7.3. Perl Interpreter Version。 - ^ Perlでコンパイルといった場合、Perlインタープリターがソースコードを読込み内部表現に置換えることです。これは移植性・相互運用性の視点からは好ましい特徴で、C/C++やJavaのように実行形式や中間表現をファイルに書出すことではありません。
- ^ gotoはあります。が、大域脱出などはラベルと併用したループ制御文で実現できるなど、gotoが必要になるケースは極めて少ないです
- ^ “strict - Perl pragma to restrict unsafe constructs - Perldoc Browser”. 2022年11月9日閲覧。
- ^ “warnings - Perl pragma to control optional warnings - Perldoc Browser”. 2021年12月11日閲覧。
</noinclude>
制御構造[編集]
この項目では、Perlの制御構造について説明します。
- 以下の構文説明では、EXPRは式、BLOCKはコードブロック、VARは変数、LISTはリスト、LABELはラベルを示します。
- 角括弧 [ ] で囲まれたものは省略可能です。
- 波括弧 { } で囲まれたものは0回以上の繰返しが可能です。
条件分岐[編集]
- かつて given/when/default 構文の実験的実装がありましたが、Perl6(現在のRaku)のテストベッドに使っただけらしく、幾つかのバグが発見され、Perl-5.24 ではレキシカルな $_ の仕様がキャンセルされるなど、言語コアにも取り込まれていないので、ここでは扱いません。
if[編集]
if文によって、ある条件をみたしているかを判定し、判定の内容により動作を切り替えることができます。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $x = 5; if ($x > 1) { say '$xの値は1より大きい'; }
- 実行結果
$xの値は1より大きい
- 上記の例の場合、変数 $x が 1 より大きいかどうかの区別を判定しています。
- 複数行の例
#!/usr/bin/perl use v5.12; use warnings; my $x = 5; if ($x > 1) { say '$xの値は1より大きい'; }
- のように改行して書いても、構いません。
else[編集]
elseは「さもなければ」という意味で、直前のif文の条件が満たされていない場合の処理を担当します。
elseのないifはありますが、ifのないelseはありえません(else節はif構文の構成要素の1つです)。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $x = 5; if ($x > 9) { say '$xの値は9より大きい'; } else { say '$xの値は9以下'; }
- 実行結果
$xの値は9以下
elsif[編集]
elsif ( 式 ) BLOCK
は、else { if ( 式 ) BLOCK }
の構文糖です。
なお、elif
でもelseif
ではなくelsif
です。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $x = 2; if ($x > 3) { say '$xは3より大きい'; } elsif ($x > 1) { say '$xは4より大きい'; } else { say '$xは1以下'; }
- 実行結果
$xの値は4より大きい
- 先行するifの条件が成立せず、elsifの条件式が成立しているのでelsifの BLOCK が実行されます(そしてelseのBLOCKは実行されません)。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $x = 5; if ($x > 3) { say '$xの値は3より大きい'; } elsif ($x > 4) { say '$xの値は4より大きい'; } else { say '$xの値は1以下'; }
- 実行結果
$xの値は3より大きい
- 先行するifの条件がしているのifのBLOCKが実行され、elsifの条件式の成否にかかわらずelsifの BLOCK は実行されません(そしてelseのBLOCKも実行されません)。
- 構文
if ( EXPR ) BLOCK { elseif (EXPR) BLOCK }* [ else BLOCK ]
unless[編集]
英語でunlessは「もし…でなければ」という意味です。
Perlのunlessは、EXPRが偽の場合、BLOCKを実行します。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $x = 5; unless ($x <= 1) { say '$xの値は1以下でない'; }
- 実行結果
$xの値は1以下でない
- 構文
unless ( EXPR ) BLOCK { elsif (EXPR) BLOCK }* [ else BLOCK ]
- unless にも任意個のelsif節と任意のelse節が後続可能です。
- else if ⇒ elsif のような、else unless ⇒ elsunless はありません。
ループ[編集]
Perlの繰返し構文には、for,while, until,do-while, do-until,foreachと基本ブロックがあります。 forとforeachはシノニムの関係にありますが、ここではループカウンターを使ったC風の繰返し構文をfor、リスト・配列やハッシュの要素を対象にイテレートする構文をforeachとしました。
for[編集]
Perlには、Cのfor文風の繰返し構文があります。
- コード例
#!/usr/bin/perl use v5.12; use warnings; for (my $i = 0; $i < 5; $i++) { say "Hello $i" } # say $i; # $i のスコープは for ループ内なのでここで参照すると、グローバル変数 $i の参照になります。
- 実行結果
Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
- my $i = 0が評価され、レキシカルスコープのループ変数$iが初期化されます。
- $i < 5が評価されます。真であれば BLOCK が実行され、文字列が出力されます。偽であればその時点でループを終了します。
- $i++が評価され、$iの値が1増加します。
- 2と3を繰り返します。
- 構文
[ LABEL ] for ( [ EXPR ]; [ EXPR ]; [ EXPR ] ) BLOCK
- カッコの中に3つの式をコンマで区切って記述します。いずれも省略可能です。
- 最初のEXPRは初期化式です。ループの開始時に1回だけ評価されます。主にループ変数の初期化に使われます。
- ここで my 宣言されたレキシカルスコープのループ変数のスコープはforループの中です。
- 次のEXPRは条件式です。BLOCKが実行される前に毎回評価され、偽となった時点でループは終了します。
- この式が最初から偽だった場合、BLOCKは1回も実行されません。(初期化式は実行されます)
- 条件式を省略した場合、真が仮定され無限ループとなります。
- 最後のEXPRは継続式です。BLOCKが実行された後に毎回評価されます。主にループ変数を変化させるのに使われます。
while[編集]
while文は、EXPRが真である限り、ブロックを実行し続けます。
for文の例と同等のものは次のようになります(厳密には $i のスコープがループを抜けた後も続くところが違います)。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 0; while ($i < 5) { say "Hello $i"; $i++; }
- 実行結果
Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
while w/ continue BLOCK[編集]
continueブロックをfor文の継続式をイミュレーションできます。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 0; while ($i < 5) { say "Hello $i"; } continue { $i++; }
- 実行結果
Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
- 構文
[ LABEL ] while ( EXPR ) BLOCK [ continue BLOCK ]
- whileは、EXPRが真である間BLOCKを繰り返し実行します。
until[編集]
untilは、EXPRが偽である限り、ブロックを実行し続けます。
for文の例と同等のものは次のようになります(厳密には $i のスコープがループを抜けた後も続くところが違います)。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 0; until($i >= 5) { say "Hello $i"; $i++; }
- 実行結果
Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
until w/ continue BLOCK[編集]
continueブロックをfor文の継続式をイミュレーションできます。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 0; until ($i => 5) { say "Hello $i"; } continue { $i++; }
- 実行結果
Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
- 構文
[ LABEL ] until ( EXPR ) BLOCK [ continue BLOCK ]
- untilは、EXPRが偽である間BLOCKを繰り返し実行します。
- つまり、 while ( EXPR ) は until ( ! EXPR ) と等価です。
do-while[編集]
doブロックにwhileが後置された場合は、まずdoブロックが一度実行されてから、whileの条件が真である間繰り返します。 doブロックはループではないので、後述する実行制御文を用いることはできません。LABELを付ける事も出来ません。
- 構文
do BLOCK while ( EXPR ) ;
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 4; do { say $i; } while ($i--);
- 実行結果
4 3 2 1 0
- 上に構文と書きましたが、実際は
EXPR1 while EXPR2
の EXPR1 がdo BLOCK
になった複合構文です。
do-until[編集]
doブロックにuntilが後置された場合は、まずdoブロックが一度実行されてから、untilの条件が偽である間繰り返します。 doブロックはループではないので、後述する実行制御文を用いることはできません。LABELを付ける事も出来ません。
- 構文
do BLOCK until ( EXPR ) ;
- 例
#!/usr/bin/perl use v5.12; use warnings; my $i = 4; do { say $i; } until ($i-- <= 0);
- 実行結果
4 3 2 1 0
- 上に構文と書きましたが、実際は
EXPR1 while EXPR2
の EXPR1 がdo BLOCK
になった複合構文です。
foreach[編集]
- 構文
[ LABEL ] foreach [ VAR ] ( LIST ) BLOCK [ continue BLOCK ]
- リストの値を順番にVARに代入し、BLOCKを実行します。
- VARはループ内のlocal変数とみなされるので、プログラムの他の場所で使用していても問題ありません。
- VARを省略した場合、local変数の$_が使われます。
- ループ内をスコープとするmy変数を使用したい場合、次のようにします:
foreach my $i ( 0..4 ) { say "Hello $i"; }
- これもfor文の例と同等ですが、while文、until文の例と同様に厳密には等価ではありません。
- foreachにもcontinueブロックを設けることが出来ます。
foreachはforのシノニム[編集]
foreachはforのシノニムで、相互に置換えることが出来ます。 一行プログラム(ワンライナー)などでは、foreachとしてforを使うことがしばしばあります。
基本ブロック[編集]
{
と }
に囲まれた基本ブロック( Basic block )が、ループの節にあるのは奇異に感じるかもしれませんが、Perl では基本ブロックは「1周しかしないループ」で、ループ制御文を使うことができます。
doブロック[編集]
doブロックは基本ブロックではなく、ブロックの最後の式の値を返す式です。 doブロックが式だからこそ、while 文修飾子 や until 文修飾子 とも結合できるのです(やる気になれば、if/until/foreach文修飾子とも結合できます)。 doブロックでは、ループ制御文を使うことはできません。
- doブロックは式
#!/usr/bin/perl use v5.12; use warnings; my $x = do { my $i = 100; $i+100 }; say $x
- 実行結果
200
- do と next の組合わせ
do {{ next if $x == $y; ... }} until $x++ > 0;
- doブロックの {} の内側に、基本ブロックの {} を入れます。
- do と last の組合わせ
{ do { last if $x == $y; ... } while $x++ <= 0 }
- doブロックの {} の外側を、基本ブロックの {} で囲みます。
defer[編集]
Perl 5.36.0 で、待望の defer が追加されました。
- deferで登録されたブロックは、スコープを抜けたときに実行されます
use v5.36.0; use feature 'defer'; no warnings "experimental::defer"; say "Befor"; { defer{ say "One" } defer{ say "Two" } defer{ say "Three" } say "Done!" } say "After";
- 実行結果
Befor Done! Three Two One After
- ブロックは、登録した逆順に実行されます。
色々な用途が考えられますが、open で開いたファイルハンドルの close 処理を defer で登録する使い方が真っ先に思いつきます。
真理値[編集]
Perlの真理値のルールはやや難解です。
- 数値
- 0は偽、それ以外は真。
- 文字列
- ""(空文字列)あるいは"0"(数値0に暗黙変換される)は偽、それ以外は真。
- リスト
- ()(空リスト)は偽、それ以外は真(これはコンテキストにも影響され、スカラコンテキストにリストを渡すと要素数になり要素ゼロの場合、数値0と評価され偽となります)。
- ハッシュ
- 要素数ゼロのハッシュは偽、それ以外は真(これはコンテキストにも影響され、スカラコンテキストにハッシュを渡すと要素数になり要素ゼロの場合、数値0と評価され偽となります)。
- undef
- 偽
多くの説明では、数値にしか言及していませんが、他にも条件式で「偽」と評価される値があります。特に文字列には注意してください。
- Perlのコード例
my $x = 1; if ($x) { print $x . 'は真'; } else { print $x . 'は偽'; }
- 結果
1は真
- 0の真理値
my $x = 0; if ($x) { print $x . 'は真'; } else { print $x . 'は偽'; }
- 結果
0は偽
- (空文字列)や’0’も偽
my @ary = (0, 1, 2, 3, '', "0", " ", "1", "2", (), (1), undef); foreach my $x(@ary) { if ($x) { print "($x)は真 "; } else { print "($x)は偽 "; } }
- 実行結果
(0)は偽 (1)は真 (2)は真 (3)は真 ()は偽 (0)は偽 ( )は真 (1)は真 (2)は真 (1)は真 ()は偽
constant プラグマを使った真理値定数の定義[編集]
- Perl 5.36.0 からは
use builtin qw(true false)
で、真理値定数 true と false が定義されたので、constant プラグマを使った真理値定数の定義は Obsolate になりました。また、builtin::is_bool()
も 5.36.0 で追加されました。
[TODO:節を改めての builtin の解説]
Perlには、他のいくつかのプログラミング言語にある、真理値定数 true と false がありませんが、constant プラグマを使うことで実現できます[1]。
- constant プラグマを利用
use constant { false => 0 != 0, true => 0 == 0 }; my @ary = (false, true); foreach my $a(@ary){ if ( $a ) { print "($a)は真 "; } else { print "($a)は偽 "; } }
- 実行結果
()は偽 (1)は真
0 != 0
が 0 ではなく ”” というのは意外ですね。
文修飾子[編集]
次の制御構文は、文修飾子( Statement Modifiers )としても使用できます[2]。
- 構文
EXPR if EXPR EXPR unless EXPR EXPR while EXPR EXPR until EXPR EXPR foreach [ VAR ] LIST
- 一文のみのごく簡単な制御の場合はこちらのほうが簡潔で、英文のような見た目になります。
- 修飾子が後になったほか、条件式を囲む括弧 ( ) が不要などの差異があります。
- Perlの(文修飾子でない)制御構文には { } が必須なのですが、文修飾子では逆に使用不可です。
- Cになれた人には、単文・複文の関係にみえますが、Perlの構文は、文:=単文 | 複文 ではなく制御構文ごとにブロックを要求したり式を要求したりします。
- 条件文
print "Good morning.\n" if 6 <= $hour and $hour < 12;
- 繰返し文
print "@{[$i++]} " while $i < 10; print "<$_> " foreach qw(abc def xyz); print "\n----\n"; $i = 0; while ($i < 10) { print "@{[$i++]} " } foreach (qw(abc def xyz)) { print "<$_> "; }
- 実行結果
0 1 2 3 4 5 6 7 8 9 <abc> <def> <xyz> ---- 0 1 2 3 4 5 6 7 8 9 <abc> <def> <xyz>
ループ制御文[編集]
ループ制御を行なう実行制御文の説明をしたいと思います。 前出のdo-while以外のループ構文と空のブロックでは、ループの挙動を制御する各種実行制御文が使用出来ます(doブロックでループ制御文を使いたい場合、基本ブロックを併用します)。 例外として、continue BLOCK 中でそれらの実行制御文を使用した場合には、直近のループブロックを制御する振舞いをします。 ラベルを指定することで入れ子になったループの制御もできます。省略した場合、もっとも内側にあるループを指定したとみなされます。
last[編集]
即座にループから脱出します。continueブロックは実行されません。
OUTER: while ( 1 ) { #無限ループ $i = 0; INNER: while ( $input = <> ) { last if $input =~ /^restart/; # 直近のINNERループを脱出 last OUTER if $input =~ /^quit/; # 明示されたOUTERループを脱出 print "$i\n"; } continue { $i++; } }
next[編集]
残りの文をスキップし、次の反復に移ります。 ループ条件式は評価されます。continueブロック、for文の継続式も評価されます。
redo[編集]
残りの文をスキップし、反復をやりなおします。 ループ条件式は評価されません。continueブロック、for文の継続式も評価されません。
continueブロック[編集]
continueブロック中の制御の例を上げます。
my $i = 0; { #1. print "OUTER\n"; { #2. $i ++ ; print "INNER\n" ; } continue { redo if $i < 10 ; print "$i\n" } }
この場合のredoは#1のブロックではなく、直近の#2ブロックを制御する振舞いをします。
変数とデーター型[編集]
変数[編集]
Perlでは、変数は「データーを格納する領域(オブジェクト)に付けられた名前」です。 同じオブジェクトを2つ以上の変数が指し示すこともありますし、配列の要素のように、単体では名前がないオブジェクトもあります。 変数を用いることにより、データーをより柔軟に扱うことができます。
変数の利用の形態は大きく分けて宣言、代入、参照の3種です。
データー型[編集]
Perlには3つの組み込みデーター型があります。
- スカラー
-
- 文字列
- サイズは問わず、使用可能なメモリ量に制限されます
- 数値
-
- 整数
- 処理系固有のネイティブな整数
- 浮動小数点数
- 処理系固有のネイティブな整数
- 文字列で表現された数値
- 上記の整数・浮動小数点数をPerlの数値リテラルで表現したもの(”NaN” ”Inf” なども含まれます)
- 参照
- これについては リファレンス で説明します
接頭辞[編集]
変数のデーター型は、接頭辞( sigil ; シジル)によって区別します。
変数の種類と接頭辞 種類 接頭辞 説明 スカラー $ 数値や文字列などの値を1つだけ保持します。 配列 @ 複数の値を、順序付きで保持します。 ハッシュ % 複数の値を、重複しないキーに結びつけ保持します。 リファレンス $ スカラー、配列あるいはハッシュのメモリ上のアドレスを保持します。 リファレンスは、特殊なスカラーなので接頭辞は同じ $
です。
データー型の種類[編集]
スカラー[編集]
スカラーは、内部に構造をもたない「ただ一つ」の値を保持できるデーター型で、接頭辞は、$
(ドルマーク;Scalar の S)です。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $name = "太郎";# レキシカル変数 $name を "太郎" で初期化 my $age = 30; # レキシカル変数 $age を 30 で初期化 say $name; say $age;
- 実行結果
太郎 30
- スカラー変数の接頭辞は、
$
(ドルマーク;Scalar の S)です。 - 数学では「スカラー」の対義語は「ベクトル」ですが、Perlでは、「リスト」が「スカラー」の対義語です。
- 数学的にはしっくりきませんが、文字列もスカラーです。
- 変数が示している値が数値か文字列かは、値側にある情報「型」により決まります。
- 上記コードでは、「name」という名称のスカラー変数 $name と、「age」という名称のスカラー変数 $age があります。
- スカラー変数 $name は、文字列 "太郎" を保持し、
- スカラー変数 $age は、数値(整数) 30 を保持します。
- このように、一つの変数は、単一の値を保持できます。
スカラーリテラルの表記[編集]
- 文字列リテラル
”ABC and Z”
や'ABC and Z'
のように、”
(ダブルクォーテーションマーク)や’
(シングルクォーテーションマーク)で囲みます。- 数値
”
や’
囲む必要はありませんが、囲んでも実行時に数値として解釈されます。また、NaN や Inf のような特殊な値は、”
や’
囲む必要があります。
変数名を含む識別子の規約[編集]
- 識別子の先頭は、英大文字・英小文字あるいは ’_’
- 識別子の2文字目以降は、英大文字・英小文字・'0'..'9' あるいは ’_’
- 識別子の長さは、1文字以上251文字以下
- 識別子の正規表現
[A-Za-z_][A-Za-z_0-9]{0,250}
- 不正な識別子の例
123age new-word フラッグ
- 先頭に数字は使えない
- ’-’は変数名に使えない
- 論外
演算子主導の型強制[編集]
Perlは、演算子式を評価するに当たり、演算子ごとにオペランドの型を強制的に変換します。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $age = 30; say __LINE__ . ": $age"; $age = $age . "1"; say __LINE__ . ": $age"; $age = $age + 1; say __LINE__ . ": $age"; $age = $age x 3; say __LINE__ . ": $age"; $age = $age / 302; say __LINE__ . ": $age";
- 実行結果
5: 30 6: 301 7: 302 8: 302302302 9: 1001001
- このように、演算子によってオペランドが数値と解釈されたり文字列と解釈されたりします。
- 逆に言うと、演算子を見ればオペランド(と式の値)の型がわかります。
次のプログラムは、等価な代入演算子による実装です。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $age = 30; say __LINE__ . ": $age"; $age .= "1"; say __LINE__ . ": $age"; $age += 1; say __LINE__ . ": $age"; $age x= 3; say __LINE__ . ": $age"; $age /= 302; say __LINE__ . ": $age";
- 実行結果
5: 30 6: 301 7: 302 8: 302302302 9: 1001001
例外的に、インクリメント演算子は数値にも文字列にも作用します。
- 例
#!/usr/bin/perl use v5.12; use warnings; my $n = 3; say __LINE__ . ": $n"; $n++; say __LINE__ . ": $n"; $n++; say __LINE__ . ": $n"; my $s = "K";say __LINE__ . ": $s"; $s++; say __LINE__ . ": $s"; $s++; say __LINE__ . ": $s"; $s = "BY"; say __LINE__ . ": $s"; $s++; say __LINE__ . ": $s"; $s++; say __LINE__ . ": $s"; $s++; say __LINE__ . ": $s";
- 実行結果
5: 3 6: 4 7: 5 9: K 10: L 11: M 13: BY 14: BZ 15: CA 16: CB
- 5-7 の数値のインクリメントは、違和感ありませんが
- 9-11 の1文字の文字列のインクリメントは、キャラクターコードを増している???と思いますが、
- 14-16 の2文字の文字列のインクリメントでは、桁上りをしています!
このような文字列をオペランドに取ったときのインクリメントをマジカルインクリメントと呼びます。
ほかのプログラミング言語との違い |
C/C++と違いPerlでは変数宣言でに、int や double などの型を指定することはありません。
Perlでは、スカラー変数に整数・浮動小数点数・文字列やリファレンスの間で暗黙の変換が働くからです。
また、Perlで「データー型」というと
などのことで、接頭辞などで区別されます。 |
配列[編集]
配列はスカラーの集合で、整数のインデックスでそれぞれの要素スカラーを参照できるデーター型で、接頭辞は、@
(アットマーク;array の a)です。
- 例
#!/usr/bin/perl use v5.12; use warnings; my @ary = ("太郎", 30); # 配列変数 @ary を、リスト ("太郎" 30) で初期化 say __LINE__ . ": $ary[0]"; # 配列変数 @ary の 0 番目の要素を参照 say __LINE__ . ": $ary[1]"; # 配列変数 @ary の 1 番目の要素を参照 say __LINE__ . ": $ary[-1]"; # 配列変数 @ary の -1 番目(最後)の要素を参照 say __LINE__ . ": $ary[-2]"; # 配列変数 @ary の -1 番目(最後から 2 番目)の要素を参照 say @ary; # そのまま文字列化すると、要素を文字列化したものを区切り文字なく連結 { local $, = ";" ; say @ary; } # {} でスコープを切って local で区切り文字グローバル変数 $, をローカライズしたので say @ary; # スコープを抜けると元通り say __LINE__ . ": \@ary = @ary"; # 文字列中で展開すると、区切り文字は1文字の空白 say __LINE__ . ": \@ary = @{[@ary]}";# ベビーカー演算子 @{[式]} でも同じ $ary[1] = 25; # 1番めの要素に 25 を代入 say __LINE__ . ": \@ary = @ary"; # 置換わる $ary[1]++; # インクリメント say __LINE__ . ": \@ary = @ary"; # 増える $ary[1] = "ABC"; # 1番めの要素に "ABC" を代入 say __LINE__ . ": \@ary = @ary"; # 置換わる $ary[1]++; # インクリメント say __LINE__ . ": \@ary = @ary"; # 増える! push @ary, "XYZ"; # push は配列の末尾に追加 say __LINE__ . ": \@ary = @ary"; # 増える(違う意味で) unshift @ary, "UVW"; # unshift は配列の先頭に追加 say __LINE__ . ": \@ary = @ary"; # 増える(また違う意味で) my $x = shift @ary; # shift は先頭要素の取出し say __LINE__ . ": $x"; # 戻値は取出した値 say __LINE__ . ": \@ary = @ary"; # 先頭がなくなった my $y = pop @ary; # pop は末尾要素の取出し say $y; # 戻値は取出した値 say __LINE__ . ": \@ary = @ary"; # 末尾がなくなった my $z = @ary; # スカラ変数へ配列変数を代入すると say __LINE__ . ": \$z = $z"; # 要素数が入る push @ary, qw(A B C D); # リストをpush(qw/STRING/の例) say __LINE__ . ": \@ary = @ary"; # 展開されて追加される foreach my $el(@ary) { # foreach ループは先頭から順位要素にブロックを適用 say __LINE__ . ": \$el = $el"; } foreach (@ary) { # ループ変数を宣言しなくても $_ で要素を参照できる say __LINE__ . ": \$_ = $_"; } say __LINE__ . ": \$_ = $_" foreach (@ary); # 同じ意味
- 実行結果
7: 太郎 8: 30 9: 30 10: 太郎 太郎30 太郎;30 太郎30 16: @ary = 太郎 30 17: @ary = 太郎 30 20: @ary = 太郎 25 23: @ary = 太郎 26 26: @ary = 太郎 ABC 29: @ary = 太郎 ABD 32: @ary = 太郎 ABD XYZ 35: @ary = UVW 太郎 ABD XYZ 38: UVW 39: @ary = 太郎 ABD XYZ XYZ 43: @ary = 太郎 ABD 46: $z = 2 49: @ary = 太郎 ABD A B C D 52: $el = 太郎 52: $el = ABD 52: $el = A 52: $el = B 52: $el = C 52: $el = D 56: $_ = 太郎 56: $_ = ABD 56: $_ = A 56: $_ = B 56: $_ = C 56: $_ = D 59: $_ = 太郎 59: $_ = ABD 59: $_ = A 59: $_ = B 59: $_ = C 59: $_ = D
- 接頭辞は、
@
(アットマーク;array の a)です。 - 配列の要素にはスカラーが入り、1つの配列に文字列や数値やリファレンスが混在することができます。
配列変数の代入の意味論[編集]
- 例
#!/usr/bin/perl use v5.30.0; use warnings; my @x = 1..10; say __LINE__ . ":\@x --> @x"; my @y = @x; say __LINE__ . ":\@y --> @y"; $y[$_] *= 2 foreach (0..$#y); say __LINE__ . ":\@x --> @x"; say __LINE__ . ":\@y --> @y";
- 実行結果
6:@x --> 1 2 3 4 5 6 7 8 9 10 9:@y --> 1 2 3 4 5 6 7 8 9 10 12:@x --> 1 2 3 4 5 6 7 8 9 10 13:@y --> 2 4 6 8 10 12 14 16 18 20
- Perlで、配列変数同士のコピーは、全ての要素の一対一の複製です。
当たり前のようですが、動的型付けの言語の中では、意外と少数派です。
- Rubyの例
x = Array(1..10) puts "#{__LINE__}:x --> #{x}" y = x puts "#{__LINE__}:y --> #{y}" y.map!{|i| i * 2} puts "#{__LINE__}:x --> #{x}" puts "#{__LINE__}:y --> #{y}"
- 実行結果
2:x --> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 5:y --> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 8:x --> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 9:y --> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
- Rubyでは、配列の代入は別名を作ることになり、同じオブジェクトを示します。
- このため、片方の変数をつかい配列要素の値を書換えると、他方から参照しても書換わります。
- 複製が欲しい場合は、Array$clone をつかいます。
- JavaScriptの例
let x = [...Array(10)].map((_, i) => i + 1) console.log(`x --> ${x}`) let y = x console.log(`y --> ${y}`) for (let i = 0, len = y.length; i < len; i++) y[i] *= 2 console.log(`x' --> ${x}`) console.log(`y' --> ${y}`)
- 実行結果
x --> 1,2,3,4,5,6,7,8,9,10 y --> 1,2,3,4,5,6,7,8,9,10 x' --> 2,4,6,8,10,12,14,16,18,20 y' --> 2,4,6,8,10,12,14,16,18,20
- JavaScript、配列の代入は別名を作ることになり、同じオブジェクトを示します。
- やはり、片方の変数をつかい配列要素の値を書換えると、他方から参照しても書換わります。
- 複製が欲しい場合は、Array$concat を無引数でつかいます。
このほか、Pythonも配列の代入は別名作成です。少数派ですが、PHPがPerlと同じです。
配列リテラル[編集]
配列にリテラルはありません。 配列リテラル風に見えるものはリストです。
リスト[編集]
リストは、スカラー・配列やハッシュのようなデーター型ではなく書式です。
配列変数の初期化にリストが使われるので紛らわしいのですが、
- 「配列変数」はあり「リスト変数」はありません。
- 「リストを返す関数」とはいいますが、「配列を返す関数」とはいいません。
- 「リストコンテキスト」とはいいますが、配列コンテキストとはいいません。
リストは、複数の変数を一括宣言したり、多値代入につかわれます。
配列とリストは似通っていますが区別する必要があります。
- 例
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my @name = ("太郎", "次郎"); my ($name1, $name2) = @name; say $name[1]; say "$name[1]"; say @name; say "@name"; my ($x, $y) = (123, 999); say "$x $y"
- 実行結果
次郎 次郎 太郎次郎 太郎 次郎 123 999
なお、
my @name = ("太郎", "次郎"); print ">$name<\n";
- 実行結果
><
- エラーにはなりませんが、
$name
は表示されません。
つぎに
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my @name = ("太郎", "次郎"); print ">$name<\n";
- エラー表示
Global symbol "$name" requires explicit package name (did you forget to declare "my $name"?) at Main.pl line 5. Execution of Main.pl aborted due to compilation errors.
- と2つのプラグマを補うと、エラーを発見してくれます。
use v5.12; use warnings;
- の2つは必ず指定しましょう。
use v5.12;
のv5.12
は、このバージョンからstrictがディフォルト化されたので使いましたが、2010/04/16 リリースなのでコレより古いリリースを使っている可能性は2022年11月現在ないと思います。また、use v5.12;
すれば say が使えるようになります。
qw演算子を使って
my @name = qw(太郎 次郎); say $name[1];
- 実行結果
次郎
qw演算子は、空白で区切った文字のシーケンスを受け取り、区切られた文字列を要素とするリストを返します。
- リストの文字列化
my @ary = (10,4,2); say @ary ;
- 実行結果
1042
- このように、リストの要素は文字列化された後、区切り文字なしに連結されます。
区切り文字[編集]
10,4,2
のように区切り文字をつけて出力したい場合、組込み関数 join を使うか、特殊変数$,を使います。
- join と $,
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my @ary = (10, 4, 2, 8); say join "," , @ary; { local $, = "'"; say @ary; } say @ary;
- 実行結果
10,4,2,8 10'4'2'8 10428
- $, はグローバルな特殊変数なので、一旦値を変えると自動的には元に戻らないので、コードブロックでスコープを切ってlocal宣言することで値を復帰できるようにします。
sort関数による並べ換え[編集]
sort関数を使うと、配列を並べ替える事ができます。 並べ替えることができますが、数値の配列であっても辞書順に並べ替えてしまいます。
- 辞書順にソート
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my @ary = (10, 4, 2, 8); say "0: @ary"; say "1: @{[ sort @ary ]}"; say "2: @{[ sort { $a <=> $b } @ary ]}"; say "3: @{[ sort { $b <=> $a } @ary ]}"; say "4: @{[ sort { $b cmp $a } @ary ]}"; say "5: @{[ sort { $a cmp $b } @ary ]}";
- 実行結果
0: 10 4 2 8 1: 10 2 4 8 2: 2 4 8 10 3: 10 8 4 2 4: 8 4 2 10 5: 10 2 4 8
1:
が辞書順になる理由は、比較が文字列として行なわれるからです。2:
の{$a <=> $b}
が追加部分ですが、$a?<=>
? $b が今までと気配が違います。- sort関数はPerl4の頃からあり、いまなら@_を使うところですが、過去のコードとの後方互換性からこの形式で残っています。
- プロトタイプ($$)を使う方法も用意されましたが、無名関数が使えないので冗長な表現になり、名前空間汚染という意味では $a $b といい勝負です。
- $aと$bは、パッケージ内に所属しているグローバル変数です(sub のように @_ で引数を受け取るのではなくグローバル変数を使っています)。
<=>
は宇宙船演算子といわれる二項演算子で、大なり(1)・等しい(0)・小なり(-1)を返します。- sort は並べ替えのアルゴリズムの「比較」の部分にこのブロックを使います。
- $aと$bは、このような出自であり use strict の「グローバル変数が使われています」のチェックをすり抜けてしまいます。
- $aと$bは、sort 以外では使ってはいけません。
- $aと$bは、sort 以外では使ってはいけません。
3:
の{$b <=> $a}
が変更部分です。左右の項を入れ替えたので逆順にソートされます。4:
の{$b cmp $a}
が変更部分です。比較演算子を文字列比較演算子としたので、辞書逆順にソートされます。5:
の{$a cmp $b}
が変更部分です。左右の項を入れ替えました。これがコードブロックを渡さなかったときのディフォルト動作です。
スライス[編集]
スライスは、配列やハッシュの部分集合へのアクセス方法を提供します。
- スライスの例
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my @ary = map { $_ * 10 } 0..9; my %hash; $hash{$_} = uc $_ foreach "a".."f"; print <<EOS; \@ary --> @ary \@ary[1,4] --> @ary[1,4] \@ary[1..4] --> @ary[1..4] \@ary[0,1,4..6] --> @ary[0,1,4..6] \@ary[9,0] --> @ary[9,0] \%hash --> @{[ map {"$_=>$hash{$_},"} sort keys %hash ]} \@hash{"a","b"} --> @{[ @hash{"a","b"} ]} \@hash{"d".."f"} --> @{[ @hash{"d".."f"} ]} \@hash{"f","a"} --> @{[ @hash{"f", "a"} ]} \@hash{qw(b e e f)} --> @{[ @hash{qw(b e e f)} ]} \@hash{"f","a"} --> @{[ @hash{"f","a"} ]} EOS say __LINE__ . ": \@ary --> @ary"; @ary[3..5] = 5..7; say __LINE__ . ": \@ary --> @ary"; @ary[5..9] = 5..100; say __LINE__ . ": \@ary --> @ary"; say __LINE__ . qq(: \%hash --> @{[ map {"$_=>$hash{$_},"} sort keys %hash ]}); @hash{"a".."c"} = "AA".."AC"; say __LINE__ . qq(: \%hash --> @{[ map {"$_=>$hash{$_},"} sort keys %hash ]}); delete @hash{"b", "e"}; say __LINE__ . qq(: \%hash --> @{[ map {"$_=>$hash{$_},"} sort keys %hash ]});
- 実行結果
@ary --> 0 10 20 30 40 50 60 70 80 90 @ary[1,4] --> 10 40 @ary[1..4] --> 10 20 30 40 @ary[0,1,4..6] --> 0 10 40 50 60 @ary[9,0] --> 90 0 %hash --> a=>A, b=>B, c=>C, d=>D, e=>E, f=>F, @hash{"a","b"} --> A B @hash{"d".."f"} --> D E F @hash{"f","a"} --> F A @hash{qw(b e e f)} --> B E E F @hash{"f","a"} --> F A 24: @ary --> 0 10 20 30 40 50 60 70 80 90 26: @ary --> 0 10 20 5 6 7 60 70 80 90 28: @ary --> 0 10 20 5 6 5 6 7 8 9 30: %hash --> a=>A, b=>B, c=>C, d=>D, e=>E, f=>F, 32: %hash --> a=>AA, b=>AB, c=>AC, d=>D, e=>E, f=>F, 34: %hash --> a=>AA, c=>AC, d=>D, f=>F,
- 配列の場合は、
@ 配列変数 [ リスト ]
の形式で、リストの要素を添字として対応した値リストがかえります。 - ハッシュの場合は、
@ ハッシュ変数 { リスト }
の形式で、リストの要素をキーとして対応した値のリストがかえります。 - 配列もハッシュも、スライスは左辺値のリストで、スライスを左辺にリストを代入すると、配列やハッシュの内容を書き換えることができます。
- スライスの引数のリストは、
,
で区切った値、..
で示した範囲(マジカルインクリメントも含む)、qw//、関数の戻値など様々なバリエーションがありえるので、強力な表現力を持ちますが、同時にパズル的に難解なコードも書けることを意味しています。
ハッシュ[編集]
ハッシュは、キーとなる文字列とスカラーの値がペアの集合のデーター型です。ハッシュは配列とは違って、順序は一定でないことが保証されます。
ハッシュ変数の接頭辞は %
です。
- 構文
%ハッシュ変数 = ( "キー1" => 値1, "キー2" => 値2, : : "キーn" => 値n, );
- キーが、Perlの識別子として有効ならば
- 構文
%ハッシュ変数 = ( キー1 => 値1, キー2 => 値2, : : キーn => 値n, );
- と書けます。
- キーを、Perlの識別子として有効にすれば
my %myHash = ("Key1" => 3, "Key2" => 4); say $myHash{"Key1"};
- は
my %myHash = (Key1 => 3, Key2 => 4); say $myHash{Key1};
- と書くことができます。
- コード例
#!/usr/bin/perl use v5.12; use warnings; my %hash = ( Tom => 18, Joe => 16, ); say __LINE__ . qq(: \$hash{Tom} -> $hash{Tom}); say __LINE__ . qq(: \$hash{Joe} -> $hash{Joe}); ##say __LINE__ . qq(: \$hash{Sam} -> $hash{Sam}); $hash{Tom}++; say __LINE__ . qq(: \$hash{Tom} -> $hash{Tom}); $hash{Joe}++; say __LINE__ . qq(: \$hash{Joe} -> $hash{Joe}); say __LINE__ . qq(: \%hash -> %hash); say __LINE__ . qq(: \@{[%hash]} -> @{[%hash]}); $hash{Sam} = 0; say __LINE__ . qq(: \@{[%hash]} -> @{[%hash]}); say __LINE__ . qq(: \@{[keys %hash]} -> @{[keys %hash]}); say __LINE__ . qq(: \@{[values %hash]} -> @{[values %hash]}); say __LINE__ . qq!: \@{[map { "\$_:\$hash{\$_}" } keys %hash]} -> @{[map { "$_:$hash{$_}" } keys %hash]}!; foreach my $k(keys %hash) { $hash{$k}++; } say __LINE__ . qq!: \@{[map { "\$_:\$hash{\$_}" } keys %hash]} -> @{[map { "$_:$hash{$_}" } keys %hash]}!; foreach (keys %hash) { $hash{$_}++; } say __LINE__ . qq!: \@{[map { "\$_:\$hash{\$_}" } keys %hash]} -> @{[map { "$_:$hash{$_}" } keys %hash]}!; $hash{$_}++ foreach (keys %hash); say __LINE__ . qq!: \@{[map { "\$_:\$hash{\$_}" } keys %hash]} -> @{[map { "$_:$hash{$_}" } keys %hash]}!;
- 実行結果
10: $hash{Tom} -> 18 11: $hash{Joe} -> 16 15: $hash{Tom} -> 19 17: $hash{Joe} -> 17 19: %hash -> %hash 20: @{[%hash]} -> Joe 17 Tom 19 23: @{[%hash]} -> Tom 19 Sam 0 Joe 17 24: @{[keys %hash]} -> Tom Sam Joe 25: @{[values %hash]} -> 19 0 17 26: @{[map { "$_:$hash{$_}" } keys %hash]} -> Tom:19 Sam:0 Joe:17 31: @{[map { "$_:$hash{$_}" } keys %hash]} -> Tom:20 Sam:1 Joe:18 36: @{[map { "$_:$hash{$_}" } keys %hash]} -> Tom:21 Sam:2 Joe:19 39: @{[map { "$_:$hash{$_}" } keys %hash]} -> Tom:22 Sam:3 Joe:20
- このように、キーに対応する値を返します。
=>
演算子はコンマ演算子と同じ働きをしますが、左オペランドの値を必ず文字列として扱うため、ハッシュを生成するときに多く用いられます。また、コンマを使うよりもキーと値の対応が明確になるという利点もあります。- ハッシュはキーと値が関連付けられたリストです。
- 値の参照
$ハッシュ変数 { キー }
- 値の参照を左辺値にすると、既存のハッシュエントリーの値の更新、あるいは存在しないキーを持ったエントリーを追加できます。
- エントリーの削除
delete $ハッシュ変数 { キー }
- ハッシュの順序
%age = ( Tom => 30, Joe => 20, ); print <<EOS; @{[%age]} EOS
- 実行結果(1)
Tom 30 Joe 20
- 実行結果(2)
Joe 20 Tom 30
- 実行するたびに、実行結果(1)と実行結果(2)がランダムに出力されます。
- 配列はデーターの並び順が決まっていますが、キーと値がペアになっているということのみが保証され、データーの順番は保証されません(保証されないどころか、セキュリティ強化のため、参照するたびに順序が変わります[3])。
- 特に Perl 5.18.0 以降は、ハッシュ実装に対する「アルゴリズム複雑化攻撃」( Algorithmic Complexity Attacks )に対して十分な強度を得るよう「ハッシュシードのランダム化」「ハッシュトラバーサルのランダム化」「バケット順序の撹乱」「新しいデフォルトのハッシュ関数」「代替ハッシュ関数 Siphash」などのセキュリティ強化が行なわれています[4]。
- 他言語の類似機能
- JsvaScript
- Objectオブジェクト(ルートオブジェクト)がハッシュ(連想配列)です。が、objectはプロトタイプも含むので Mapオブジェクトのほうがより近いです。
- Python
- 辞書型
- Ruby
- Hashクラス
- AWK
- AWKの配列は連想配列です。
Perlが扱うデーター[編集]
Perlでは、演算子によってオペランドの型が決まるので、それに合わせて暗黙の型変換が起こります。 これは、明示的な型変換の手間を省く一方、プログラマーの意図とは異なる変換が行なわれる危うさも含んでいます。
- 例
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; my $x = 52; my $y = "nd street"; say $x + $y; say $x . $y;
- 実行結果
52 52nd street
- 実行時エラー
Argument "nd street" isn't numeric in addition (+) at Main.pl line 6.
use warnings;
で警告を有効にしたので、文字列が0に暗黙変換されたことが指摘されています。
文字列リテラル[編集]
「Hello World」 のような文字列をPerl で扱う場合、"
(ダブルクォーテーション)で囲みます。
- 例
"Hello World"
シングルクォーテーション ' ' で文字列を囲むことも出いますが、
\n
などのバックスラッシュエスケープシーケンスが置換わらない。- 変数や式が展開されない。
この2点がダブルクォーテーションで囲んだ場合と異なります。
型強制[編集]
- 例
use v5.30.0; use warnings; my $x = "123"; my $y = 654; say $x . $y; say $x + $y;
- 実行結果
123654 777
.
(ピリオド ; 文字列連結演算子) は、両辺を文字列に暗黙のうちに変換して連結した文字列を返します。+
(プラス ; 数値加算演算子) は、両辺を数値に暗黙のうちに変換して和を返します。
このように、Perlでは演算子がオペランドを暗黙に変換するので、演算子ごとのオペランド型の理解が大切になります。
引用符と引用符類似演算子[編集]
通常、引用符で囲まれた文字列は、リテラル値として考えられていますが、Perlでは演算子として機能し、様々な種類の補間やパターンマッチの機能を提供します。 Perlでは、これらの動作のために通常の引用符が用意されていますが、任意の引用符を選択する方法も用意されています。 次の表では、{}は区切り文字のペアを表しています。
引用符と引用符類似演算子 慣用表記 汎用表記 意味 変数や式の展開 '' q{} リテラル 不可 "" qq{} リテラル 可 `` qx{} コマンド 可† qw{} 単語リスト 不可 // m{} パターンマッチ 可† qr{} パターン 可† s{}{} 置換 可† tr{}{} 変換 不可‡ y{}{} 変換 不可‡ <<EOF ヒアドキュメント 可† †:'' がデリミタでない場合に限ります。
‡:一定の条件で可 tr の項目参照。
数値[編集]
Perlの数値は、内部的にはネイティブな整数・ネイティブな浮動小数点数・数値を示す文字列で記憶します。 数値リテラルは、10進数、2進数(0bを前置), 8進数(0あるいは0oを前置), 16進数(0xを前置)によって数値を表現できます。 また、指数表現も可能です。
- 例
use v5.34; use warnings; print <<EOS; 42\t--> @{[ 42 ]} 0b1101\t--> @{[ 0b1101 ]} 0177\t--> @{[ 0177 ]} 0o333\t--> @{[ 0o333 ]} 0xff\t--> @{[ 0xff ]} 3.14\t--> @{[ 3.14 ]} 5.00e3\t--> @{[ 5e3 ]} EOS
- 実行結果
42 --> 42 0b1101 --> 13 0177 --> 127 0o333 --> 219 0xff --> 255 3.14 --> 3.14 5.00e3 --> 5000
非数:NaNと無限大:Inf[編集]
Perlは、数値としての非数(NaN)と無限大(Inf)をサポートしています。 ただし、大概のNaNやInfが返りそうな演算では例外が上がって来ますし、数値リテラルとしての NaN や Inf はなく、"NaN" と "Inf" をつかいます。 このとき、大文字小文字を問わず単純な先頭一致なので、以下のような少し面倒な状況がおこります。
- 例
use v5.30.0; # v5.12 以降は use strict の機能を含んでいます。 use warnings; eval { my $x = 1.0/0.0 }; # JavaScript, Ruby では無限大がかえる warn $@ if $@; # Perl では、Illegal division by zero eval { my $x = 0.0/0.0 }; # JavaScript, Ruby では非数がかえる warn $@ if $@; # Perl では、Illegal division by zero say 0+"information"; say 0+"nano"; my $huge = 10**1010; say $huge; say -$huge; say $huge - $huge;
- 実行時の警告
Illegal division by zero at Main.pl line 4. Illegal division by zero at Main.pl line 7. Argument "information" isn't numeric in addition (+) at Main.pl line 10. Argument "nano" isn't numeric in addition (+) at Main.pl line 11.
- 実行結果
Inf NaN Inf -Inf NaN
- 数値としての無限大は ”Inf” に、非数は ”NaN” に正規化されます。
- 単純な文字列から数値への変換(Perlが常々行う暗黙の強制変換でも)無限大や非数に転んでしまう危うさあることを示しています。
変数 $n
があるとき、 $n != $n
が真なら NaN、abs($n) == "Inf"
が真なら Inf または -Inf です。
演算誤差と精度保証[編集]
Perlに限らず、数値計算には誤差が伴います。 例えば、0.01 を 100 回足しても 1 にはなりません。 これを保証する方法はいくつかありますが、ここではカハンの加算アルゴリズムを紹介します。
- 例
use v5.30; # v5.12 以降は use strict の機能を含んでいます。 use warnings; my ( $delta, $iter ) = ( 0.01, 100 ); my $sum = 0.0; $sum += $delta foreach ( 1 .. $iter ); say sprintf "素朴な実装:\t\t%.55f", $sum; $sum = 0; my $c = 0; foreach ( 1 .. $iter ) { my $y = $delta - $c; my $t = $sum + $y; $c = ( $t - $sum ) - $y; $sum = $t; } say sprintf "カハンの加算アルゴリズム:\t%.55f", $sum; use List::Util qw(sum); my @v; push @v, $delta foreach ( 1 .. $iter ); say sprintf "List::Util::sum:\t%.55f", List::Util::sum @v;
- 実行結果
素朴な実装: 1.0000000000000006661338147750939242541790008544921875000 カハンの加算アルゴリズム: 1.0000000000000000000000000000000000000000000000000000000 List::Util::sum: 1.0000000000000006661338147750939242541790008544921875000
- List::Utilモジュールのsumが、素朴な実装と同じ値というのはいがいでした。
特殊変数[編集]
プログラマーが変数を宣言しなくても、いくつかの変数は機能が決まっていて、事前にPerlに用意されており、このような変数を特殊変数あるいは処理系定義済み変数と言います。
プログラム名[編集]
たとえば特殊変数 $0 は、プログラム名が代入されています。
- 例
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; say $0; say `ps -x`; $0 = "(secret)"; say $0; say `ps -x`;
- 実行結果
Main.pl PID TTY STAT TIME COMMAND 10 ? S 0:00 /bin/sh ./exec_command 11 ? S 0:00 perl Main.pl 12 ? R 0:00 ps -x (secret) PID TTY STAT TIME COMMAND 10 ? S 0:00 /bin/sh ./exec_command 11 ? S 0:00 (secret) 13 ? R 0:00 ps -x
- $0 は、値を参照するだけでなく上書きすることもできます。
- 値を上書きすると、Perlのスクリプトから参照できる値が変わるだけでなく、環境も書換えます。
$^O:OS名[編集]
$^T:プロセス開始時刻[編集]
$^V:perlインタープリタバージョン[編集]
$$:プロセスID[編集]
- 例
use v5.12; # v5.12 は use strict の機能を含んでいます。 use warnings; print <<EOS; \$^O: $^O\t-- OS名 \$^T: $^T\t-- プロセスの開始時刻(エポックからの通算秒) \$^V: $^V\t-- perl インタープリターバージョン \$\$: $$\t-- Process ID EOS
- 実行結果
$^O: linux -- OS名 $^T: 1668142037 -- プロセスの開始時刻(エポックからの通算秒) $^V: v5.30.0 -- perl インタープリターバージョン $$: 11 -- Process ID
コンテキスト[編集]
変数、関数、定数などが、式の中でどのように評価されるか決定するものです。
大別するとスカラー・コンテキストとリスト・コンテキストがあり、スカラー・コンテキストにおかれた値はスカラーとして、リスト・コンテキストにおかれた値はリストとして評価されます。
コンテキストと実際のデーターが食い違っている場合、次のような規則で評価されます。
- スカラー・コンテキストにリストがおかれた場合、リストの最後の要素が評価されます(コンマ演算子の為)。
- リスト・コンテキストにスカラーがおかれた場合、そのスカラー1個だけを要素とするリストであると解釈されます。
どのようにコンテキストが提供されるか、以下にいくつか例を示します。
代入式は右辺に、左辺と同じコンテキストを提供します:
- コード例
my @array = qw(Foo Bar Baz); my $var = @array; print $var
- 実行結果
3
- qw は、つづく丸カッコ内をスペースで区切ってリスト化する演算子です。
配列はスカラー・コンテキストで評価されるとその要素数を返すので、結果として$numberには3が代入されます。
ただしこのような結果になるのは配列だけです。
前述したとおり、リストがスカラー・コンテキストで評価されると、最後の要素が返されます:
- コード例
my $var = qw(Foo Bar Baz); my ($foo, $bar, $baz) = 'Foo'; print <<EOS; $var ($foo), ($bar), ($baz) EOS
- 実行結果
Baz (Foo), (), ()
- 右辺はスカラーですが、左辺がリスト値を期待している為、1つの要素'Foo'のみを持つリストと解釈されます。
これが $foo に代入されますが、残りの2つの変数については、対応する右辺値がない為未定義となります。
したがって、これは次のコードと等価です:
my ($foo, $bar, $baz) = ('Foo', undef, undef);
フォワード宣言されたサブルーチンは、デフォルトで引数にリスト・コンテキストを提供します:
sub user_func; user_func 'foo', 'bar', 'baz';
これは次のように解釈されます。
user_func('foo', 'bar', 'baz');
つまり、括弧のないサブルーチン呼び出しはリスト演算子として扱われます。
もしこれを、
user_func('foo'), 'bar', 'baz'
と解釈させたいのなら、フォワード宣言にプロトタイプを付加することによって単項演算子として解釈させることができます:
sub user_func($); # 実装にもプロトタイプが必要 user_func 'foo', 'bar', 'baz';
スカラー・コンテキストはさらに
に細分され、評価されます。
文字列コンテキスト[編集]
長さに制限のない文字列として扱われます。
数値はそのまま文字列に変換され、未定義値は空文字列になります。リファレンスも文字列になりますが、文字列として処理されたリファレンスを再びリファレンスに戻すことはできません:
my ($var, $refvar, $refstr); $var = 'foo'; $refvar = \$var; #$$refvar eq 'foo' $refstr = "$refvar"; # 文字列として格納 $$refstr; #エラー; $refstrはもはやリファレンスではない
数値コンテキスト[編集]
数値リテラルとして解釈できる文字列は数値として扱われます。それ以外の文字があるとそこで解釈が終了します。
- 例
#!/usr/bin/perl use v5.12; use warnings; say sprintf __LINE__ . ": %d", 0 + '12345'; say sprintf __LINE__ . ": %d", 0 + '12345abcde'; say sprintf __LINE__ . ": %d", 0 + '123.45e2'; say sprintf __LINE__ . ": %d", 0 + '0b11000000111001'; say sprintf __LINE__ . ": %d", 0 + '012345'; say sprintf __LINE__ . ": %#x", 0 + '0x12345'; say sprintf __LINE__ . ": %#o", oct '12345'; say sprintf __LINE__ . ": %#x", hex '12345';
- 実行時エラー
Argument "12345abcde" isn't numeric in addition (+) at Main.pl line 6. Argument "0b11000000111001" isn't numeric in addition (+) at Main.pl line 8. Argument "0x12345" isn't numeric in addition (+) at Main.pl line 10.
- 実行結果
5: 12345 6: 12345 7: 12345 8: 0 9: 12345 10: 0x12345 11: 012345 12: 0x12345
- 先頭に'0'があっても8進数とは解釈されませんが’0x’が先頭にあると16進数として評価されます。
- 基数を明示して変換するには oct() 関数や hex() 関数を利用します。
真偽値コンテキスト[編集]
ifやwhileなどの制御構文や修飾文、andやorなどの論理演算子が提供するコンテキストです。
偽となるものは:
- 数値
0
- 要素数0の配列
- 要素数0のリスト
- 要素数0のハッシュ
- 文字列
'0'
- 空文字列
''
- 未定義値
undef
であり、残りは全て真と解釈されます。
「文字列'0'」とは'0'という文字列のことであり、数値コンテキストで0と解釈される文字列全てのことではないので注意してください。
次のものは全て真となります:
'0.0'; 'aaa'; '0 but true';
無効コンテキスト[編集]
評価した結果が捨てられてしまうので、値を期待しないコンテキストです。戻り値のない関数呼び出しなど、副作用を目的として使われます。
副作用もないコードは、perlに-wスイッチをつけて実行すると警告が発せられます:
'literal';
型グロブ[編集]
Perlでは異なるデーター型に対して同じ識別子を与えることができます:
$foo = 'bar'; @foo = ( 'bar', 'baz' ); %foo = ( bar => 'baz' ); sub foo { return 'bar' };
Perl処理系は内部に識別子テーブルと呼ばれるハッシュを持っています。そのキーは識別子であり、対応する値は型グロブというデーター構造です。型グロブは同じ識別子を持つすべてのデーター型へのリファレンスを格納しています。つまり上記の例だと識別子'foo'の型グロブにはスカラー、配列、ハッシュ、サブルーチンという4つのデーター型へのリファレンスが格納されています。型グロブは識別子の前に'*'というプレフィックスを付加して表現されます:
*foo;
型グロブ自身はリファレンスを格納したハッシュであり、キーはデーター型の名前です:
*foo{SCALAR}; # \$foo *foo{ARRAY}; # \@foo *foo{HASH]; # \%foo *foo{CODE}; # \&foo *foo{GLOB}; # \*foo; 自分自身へのリファレンス *foo{IO}; # ファイルハンドル *foo{FORMAT} # フォーマット
型グロブへの代入[編集]
型グロブもデーター構造の一つですから、代入や評価ができます。型グロブに別の型グロブを代入すると、変数の別名(エイリアス)を定義することが出来ます:
$foo = 'FOO'; @foo = ( 'FOO', 'BAR' ); *bar = *foo; $bar = 'BAR'; push( @bar, 'BAZ' ); print $foo, "\n"; #BAR print @foo, "\n"; #FOOBARBAZ
これはかつてPerlにリファレンスがなかった頃、サブルーチンに引数を参照渡しするのに利用されていました。また、ファイルハンドルとフォーマットにはプレフィックスが存在しないので、これらを受け渡しする場合の唯一の手段でもありました。
for ( $i = 0; getline( *line ) != -1; $i++ ) { print "line $i: $line"; } sub getline { local (*l) = @_; return defined( $l = <STDIN> ) ? length( $l ) : -1; }
現在ではリファレンスが利用できるので、型グロブを使う必要はありません。ファイルハンドルやフォーマットに関してもIOモジュールなどでオブジェクトとして扱うことができます。
なお、型グロブは識別子テーブルの実体そのものですから、ブロックに結び付けられたレキシカルスコープにすることはできません。言い換えると、local変数にはできるがmy変数にはできません。
また、特定のデーター型のリファレンスを代入すると、そのデーター型に限定して別名を定義できます:
$foo = 'FOO'; @foo = ( 'FOO', 'BAR' ); *bar = \@foo; #配列のみ別名を定義 $bar = 'BAR'; push( @bar, 'BAZ' ); print $foo, "\n"; #FOO print @foo, "\n"; #FOOBARBAZ
*qux = \&Foo::Bar::baz; # Foo::Barモジュールのbaz関数をqux関数としてインポートする
演算子[編集]
演算子とは、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 となります。
演算子の優先度と結合方向[5] 演算子 結合方向 項 リスト演算子(左から) 左 -> 左 ++ -- 無結合 ** 右 ! ~ ~. \ +項 -項 右 =~ !~ 左 * / % x 左 + - . 左 << >> 左 名前付き単項演算子 無結合 isa 無結合 < > <= >= lt gt le ge 連鎖[6] == != eq ne <=> cmp ~~ 連鎖/無結合[6] & &. 左 | |. ^ ^. 左 && 左 || // 左 .. ... 無結合 ?: 右 = += -= *= などの代入演算子 goto last next redo dump 右 , => 左 リスト演算子 (右から) 無結合 not 右 and 左 or xor 左
代入演算子[編集]
=[編集]
- コード例
#!/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が "" に自動変換され右辺の値と結合…つまり普通の代入が行なわれます。
x=[編集]
- 例
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[編集]
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[編集]
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[編集]
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[編集]
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
qr[編集]
正規表現リテラルの一般化
$x = qr/^Regexp$/i;
qx[編集]
バッククォートリテラルの一般化
$x = qx/uname -a/; # `uname -a`; と同じ
ヒアドキュメント[編集]
<<EOF[編集]
行指向のクォートの形式は、シェルのヒアドキュメント構文に基づくものです。 << の後に引用を終了する文字列を指定すると、現在の行から終了文字列までのすべての行が、その項目の値となります。
終了文字列の前に ~ を付けると、「インデント付き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
の方が優先順位が低いことが違います。「単語より演算子らしい記号のほうが強い」とおぼえてください。
||[編集]
||
は、論理和を返す二項演算子です。
- 例
# Your code here! 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
は、優先度が低いバージョンの ||
演算子です。
短絡評価[編集]
論理和は左引数が偽である場合のみ右引数の評価を行います。 このような論理演算子の実質的に制御構造としての振る舞いを「短絡評価」とよびます。 論理和はまた、最後に評価された値を返すので例外処理にも使われます。 このとき 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[編集]
and
は、優先度が低いバージョンの &&
演算子です。
論理積も短絡評価を行います。
//[編集]
この //
は、正規表現のそれではなく /
2文字からなるトークンで、||
とよく似ていますが、左辺が定義さていれば左辺を、定義されていなければ右辺を返します。オプショナルな引数の定義状況のテストを意図されています。
my $x = defined $opt ? $opt : "no";
を
my $x = $opt // "no";
と簡素に書くことができます。
//
は、5.10 で追加されました。
not[編集]
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以下
eq[編集]
ne[編集]
両辺の文字列が、文字列として評価した場合に、同じ値かを調べるときに使用します。
なお、== および != は両辺が数値として評価した場合なので、意味が違います。
Perlには変数に型が無いので、C言語とは異なり、比較演算子の側で、変数の内容を数値として評価するか、内容を文字列として評価するかの指定が必要になるのです。
if ($x eq $y) { # この部分は$xが$yと同じ文字列のときに実行されます } if ($x ne 'correct')) { # この部分は$xに代入されている文字列が 'correct' でなかったときに実行されます }
eq は、両辺を文字列として比較したときに、両辺が同じであることを要求します。
なお「eq」とは equal (等号、等しい)の略であるとされる。
ne は、両辺を文字列として比較したときに、両辺が異なることを比較します。
「ne」とは not equal の略だとされる。
le[編集]
ge[編集]
lt[編集]
gt[編集]
二つの文字列の辞書順での大小を比較します。
if ($x le $y) { # この部分は$xが$y以下のときに実行されます } ; le -- less than or equal -- 以下 ; ge -- greater than or equal -- 以上 ; lt -- less than -- より小さい(未満) ; gt -- greater than -- より大きい(超)
cmp[編集]
二つの文字列の辞書順での大小関係により-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///[編集]
- s/PATTERN/STRING/
PATTERNにマッチするものをSTRINGに置換します。PATTERNは正規表現です。
$str = "Wiki"; $str =~ s/(Wiki)/$1pedia/; print $str; # Wikipedia
パターン変換演算子[編集]
tr///[編集]
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///[編集]
y/PATTERN1/PATTERN2/ tr///の同義語です。
秘密の演算子[編集]
Perl には、秘密の演算子( secret operators )と呼ばれる一連の独特の記法があります[7]。 これらは実際には演算子ではないのですが、高い頻度でコード上に登場するので愛称がつけられたものです。
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 のスカラーを削除
Venus[編集]
ビーナス演算子は、式を強制的に数値化します。
- 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:例]
関数[編集]
関数とは[編集]
Perlの「関数」は、与えられた値に基づいて定義された独自の処理を実行し、その結果を返す一塊のコードのことです。
英語では関数のことを function と呼び、「機能」と訳すことができます。
Perlの「関数」には、言語コアで定義済みの「組込み関数」とユーザーが定義する「サブルーチン」とがあります。
サブルーチンをつくる場合にも、最終的には、プログラマーの手により「組込み関数」「式」や「文」をくみあわせて作成することになります。
前節で紹介した print
関数は、組込み関数です。
このように、組込み関数は、名前を使って呼出すだけで使えます。
いっぽう、サブルーチンは、名前を使って呼び出す以前に、処理の内容もプログラマーが作成する(サブルーチを定義する)必要があります。
組込み関数[編集]
Perlの言語コアで定義済みの関数のことを「組込み関数」と言います。
中には my, use や do の様に、見るからに構文要素なものも「組込み関数」に分類されています。
基本的な関数[編集]
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;
use feature "say";
- say を名指しで有効化しています。お勧めです。
use feature qw(say switch);
- の様に2つ以上を列挙することもできます。
use feature ':5.10';
- バージョン 5.10 以降の機能を全て有効にします。手早く動かすためにはいいのですが過剰です。
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 ); foreach my $n (@_) { next if $n == 0; return $n if $n != $n; # for NaN my $arg = abs($n); return $n if $n == "Inf"; # for Inf if ( $arg > $max ) { $s *= ( $max / $arg ) * ( $max / $arg ) if $max != 0; $max = $arg; } $s += ( $arg / $max ) * ( $arg / $max ); } 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 != $n
とabs($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のように式を文にするのではなく、式と式を区切るデリミターなので最後の式の後に;
は不要です。
- Perl の
- 戻値とは関係ありませんが、
- 文字列が数値に自動変換される
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 と違い最初しか初期化されず、再び同じサブルーチンを呼ばれたときには前の値を憶えています。またサブルーチンの外から参照する方法はありません。
- 20行目の
- メモ化は、一度計算した答えを記憶して次からは記憶から答える戦略なので、ベンチマークに有利です。
- メモ化を行うアルゴリズムと行なわないアルゴリズムでは、ベンチマークのような繰り返しに関する感受性が違います。繰返し回数に対し線形に時間が増えないアルゴリズムはメモ化を行っている可能性があるので、ループの底で使われるのには適していますが、頻度の低い使い方の場合、性能が予想より悪い可能性があります。
- このことから、実際のプログラムのプロファイル結果とベンチマークの結果の傾向の比較も重要になります。
- メモ化を行うアルゴリズムと行なわないアルゴリズムでは、ベンチマークのような繰り返しに関する感受性が違います。繰返し回数に対し線形に時間が増えないアルゴリズムはメモ化を行っている可能性があるので、ループの底で使われるのには適していますが、頻度の低い使い方の場合、性能が予想より悪い可能性があります。
無名再帰[編集]
サブルーチン自身へのリファレンス __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 でコードブロックに引数を渡すこともできるようにしました。
[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[編集]
- 書式
index STR, SUBSTR [, POSITION]
- 機能
文字列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])
- 機能
- 文字列STRの中で、部分文字列SUBSTRが最後に出現する位置を返します。
- 組込み関数 rindex
#!/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])
文字列 EXPR から、OFFSET 目以降のバイト列を返します。取り出す長さ LENGTH をバイト単位で指定できますが、省略した場合は文字列の最後まで取り出します。なお、utf8プラグマが有効な場合は、バイト単位ではなく文字単位で取り出すことができます。
位置情報 OFFSET は上述のとおり 0 から始まりますが、LENGTH は容量なので通常は 1 以上の値を指定します。
文字列 REPLACEMENT を指定すると、取り出される部分を REPLACEMENT で置換します。
- 組込み関数 rindex
#!/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[編集]
- 書式
uc ([EXPR])
- 文字列 EXPR を大文字にして返します。EXPR を省略すると、$_ が使われます。
ucfirst[編集]
- 書式
ucfirst ([EXPR])
- uc と同じですが、先頭1文字を大文字にして返します。
lc[編集]
- 書式
lc ([EXPR])
- uc と同じですが、小文字にして返します。
lcfirst[編集]
- 書式
lcfirst ([EXPR])
- ucfirst と同じですが、小文字にして返します。
chop[編集]
- 書式
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[編集]
- 書式
chomp VARIABLE chomp (LIST)
- 変数 VARIABLE の末尾の $/(デフォルトは "\n")を削除します。
- 変数のリストを渡された場合は、各変数について同じ処理を行います。
- VARIABLE を省略すると $_ が使われます。
chr[編集]
- 書式
chr [NUMBER]
- 文字セットで NUMBER 番目に割り当てられている文字を返します。
- NUMBER を省略すると $_ が使われます。
- 逆の操作を行うには ord を使います。
crypt[編集]
- 書式
crypt PLAINTEXT, SALT
- C ライブラリの crypt(3) をエミュレートします。
hex[編集]
- 書式
hex [EXPR]
- 十六進数 EXPR を十進数に変換して返します。EXPR を省略すると $_ が使われます。
length[編集]
- 書式
length [EXPR]
- 文字列 EXPR の長さを返します。bytes プラグマが有効な場合(デフォルト)はバイト数を、utf8 プラグマが有効な場合は文字数を返します。EXPR を省略すると $_ が使われます。
oct[編集]
- 書式
oct [EXPR]
- 八進数 EXPR を十進数に変換して返します。EXPR を省略すると $_ が使われます。
ord[編集]
- 書式
ord [EXPR]
- 文字列 EXPR の文字セット上でのコード位置を返します。EXPR を省略すると $_ が使われます。逆の操作を行うには chr を使います。
pack[編集]
- 書式
pack TEMPLATE, LIST
- LIST を TEMPLATE に従ってバイナリデータに変換します。
q[編集]
q/STRING/ qq/STRING/ qr/STRING/ qx/STRING/ qw/STRING/
シングルクォート、ダブルクォート、正規表現、バッククォート、単語クォート。詳細は演算子の章を参照。
reverse[編集]
- 書式
reverse LIST
- リストコンテキストでは LIST の順番を逆順にしたリストを返します。スカラーコンテキストでは LIST の要素を結合した後に逆順にした文字列を返します。
- 例
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
- LIST を FORMAT に従って整形して返します。
tr[編集]
- 書式
tr///
- 1文字を対応する1文字に置換します。詳細は演算子の章を参照。
y[編集]
- 書式
y///
- tr///と同義。
正規表現とパターンマッチ[編集]
- m//, pos, qr//, quotemeta, s///, split, study
数値演算関数[編集]
- abs, atan2, cos, exp, hex, int, log, oct, rand, sin, sqrt, srand
配列操作[編集]
- each, keys, pop, push, shift, splice, unshift, values
リスト操作[編集]
- grep, join, map, qw//, reverse, sort, unpack
ハッシュ操作[編集]
- delete, each, exists, keys, values
I/O[編集]
- 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
Misc.[編集]
- 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
組込み関数一覧[編集]
ARRAY[編集]
each keys pop push shift splice unshift values
each[編集]
retrieve the next key/value pair from a hash
keys[編集]
retrieve list of indices from a hash
pop[編集]
remove the last element from an array and return it
push[編集]
append one or more elements to an array
shift[編集]
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
pack[編集]
convert a list into a binary representation
read[編集]
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[編集]
convert binary structure into normal perl variables
vec[編集]
test or set particular bits in a string
File[編集]
-X chdir chmod chown chroot fcntl glob ioctl link lstat mkdir open opendir readlink rename rmdir select stat symlink sysopen umask unlink utime
-X[編集]
a file test (-r, -x, etc)
chdir[編集]
change your current working directory
chmod[編集]
changes the permissions on a list of files
chown[編集]
change the ownership on a list of files
chroot[編集]
make directory new root for path lookups
fcntl[編集]
file control system call
glob[編集]
expand filenames using wildcards
ioctl[編集]
system-dependent device control system call
link[編集]
create a hard link in the filesystem
lstat[編集]
stat a symbolic link
mkdir[編集]
create a directory
open[編集]
open a file, pipe, or descriptor
opendir[編集]
open a directory
readlink[編集]
determine where a symbolic link is pointing
rename[編集]
change a filename
rmdir[編集]
remove a directory
select[編集]
reset default output or do I/O multiplexing
stat[編集]
get a file's status information
symlink[編集]
create a symbolic link to a file
sysopen[編集]
open a file, pipe, or descriptor
umask[編集]
set file creation mode mask
unlink[編集]
remove one link to a file
utime[編集]
set a file's last access and modify times
Flow[編集]
break caller continue die do dump eval evalbytes exit __FILE__ goto last __LINE__ next __PACKAGE__ redo return sub __SUB__ wantarray
break[編集]
break out of a C<given> block
caller[編集]
get context of the current subroutine call
continue[編集]
optional trailing block in a while or foreach
die[編集]
raise an exception or bail out
do[編集]
turn a BLOCK into a TERM
dump[編集]
create an immediate core dump
eval[編集]
catch exceptions or compile and run code
evalbytes[編集]
similar to string eval, but intend to parse a bytestream
exit[編集]
terminate this program
__FILE__[編集]
the name of the current source file
goto[編集]
create spaghetti code
last[編集]
exit a block prematurely
__LINE__[編集]
the current source line number
next[編集]
iterate a block prematurely
__PACKAGE__[編集]
the current package
redo[編集]
start this loop iteration over again
return[編集]
get out of a function early
sub[編集]
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
HASH[編集]
delete each exists keys values
delete[編集]
deletes a value from a hash
each[編集]
retrieve the next key/value pair from a hash
exists[編集]
test whether a hash key is present
keys[編集]
retrieve list of indices from a hash
values[編集]
return a list of the values in a hash
I/O[編集]
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[編集]
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
die[編集]
raise an exception or bail out
eof[編集]
test a filehandle for its end
fileno[編集]
return file descriptor from filehandle
flock[編集]
lock an entire file with an advisory lock
format[編集]
declare a picture format with use by the write() function
getc[編集]
get the next character from the filehandle
print[編集]
output a list to a filehandle
printf[編集]
output a formatted list to a filehandle
read[編集]
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
say[編集]
output a list to a filehandle, appending a newline
seek[編集]
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
tell[編集]
get current seekpointer on a filehandle
telldir[編集]
get current seekpointer on a directory handle
truncate[編集]
shorten a file
warn[編集]
print debugging info
write[編集]
print a picture record
LIST[編集]
grep join map qw/STRING/ reverse sort unpack
grep[編集]
locate elements in a list test true against a given criterion
join[編集]
join a list into a string using a separator
map[編集]
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[編集]
sort a list of values
unpack[編集]
convert binary structure into normal perl variables
Math[編集]
abs atan2 cos exp hex int log oct rand sin sqrt srand
abs[編集]
absolute value function
atan2[編集]
arctangent of Y/X in the range -PI to PI
cos[編集]
cosine function
exp[編集]
raise I<e> to a power
hex[編集]
convert a hexadecimal string to a number
int[編集]
get the integer portion of a number
log[編集]
retrieve the natural logarithm for a number
oct[編集]
convert a string to an octal number
rand[編集]
retrieve the next pseudorandom number
sin[編集]
return the sine of a number
sqrt[編集]
square root function
srand[編集]
seed the random number generator
Misc[編集]
defined formline lock prototype reset scalar undef
defined[編集]
test whether a value, variable, or function is defined
formline[編集]
internal function used for formats
lock[編集]
get a thread lock on a variable, subroutine, or method
prototype[編集]
get the prototype (if any) of a subroutine
reset[編集]
clear all variables of a given name
scalar[編集]
force a scalar context
undef[編集]
remove a variable or function definition
Modules[編集]
do import no package require use
do[編集]
turn a BLOCK into a TERM
import[編集]
patch a module's namespace into your own
no[編集]
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
use[編集]
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
local[編集]
create a temporary value for a global variable (dynamic scoping)
my[編集]
declare and assign a local variable (lexical scoping)
our[編集]
declare and assign a package variable (lexical scoping)
package[編集]
declare a separate global namespace
state[編集]
declare and assign a persistent lexical variable
use[編集]
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
bless[編集]
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
ref[編集]
find out the type of thing being referenced
tie[編集]
bind a variable to an object class
tied[編集]
get a reference to the object underlying a tied variable
untie[編集]
break a tie binding to a variable
use[編集]
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
alarm[編集]
schedule a SIGALRM
exec[編集]
abandon this program to run another
fork[編集]
create a new process just like this one
getpgrp[編集]
get process group
getppid[編集]
get parent process ID
getpriority[編集]
get current nice value
kill[編集]
send a signal to a process or process group
pipe[編集]
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
sleep[編集]
block for some number of seconds
system[編集]
run a separate program
times[編集]
return elapsed time for self and child processes
wait[編集]
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
m//[編集]
match a string with a regular expression pattern
pos[編集]
find or set the offset for the last/next m//g search
qr/STRING/[編集]
compile pattern
quotemeta[編集]
quote regular expression magic characters
s///[編集]
replace a pattern with a string
split[編集]
split up a string using a regexp delimiter
study[編集]
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
bind[編集]
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
recv[編集]
receive a message over a Socket
send[編集]
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///
chomp[編集]
remove a trailing record separator from a string
chop[編集]
remove the last character from a string
chr[編集]
get character this number represents
crypt[編集]
one-way passwd-style encryption
fc[編集]
return casefolded version of a string
hex[編集]
convert a hexadecimal string to a number
index[編集]
find a substring within a string
lc[編集]
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
oct[編集]
convert a string to an octal number
ord[編集]
find a character's numeric representation
pack[編集]
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
tr///[編集]
transliterate a string
uc[編集]
return upper-case version of a string
ucfirst[編集]
return a string with just the next letter in upper case
y///[編集]
transliterate a string
SysV[編集]
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
semop[編集]
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
Time[編集]
gmtime[編集]
convert UNIX time into record or string using Greenwich time
localtime[編集]
convert UNIX time into record or string using local time
time[編集]
return number of seconds since 1970
times[編集]
return elapsed time for self and child processes
User[編集]
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
入出力・コマンドラインオプション[編集]
ファイルI/Oとコマンドラインオプションについて解説します。
外部ファイルに書き込みたい場合[編集]
open(my $handle, ">" , "testperl.txt") or die; print $handle "zzzzz";
- 解説
- まず、外部ファイルに読み書きしたい場合、組み込み関数の open関数 で目的のファイルを開きます。
- ファイルは、open することで、読み出し・書き込み・追加が可能になります。
open(某) or die
は、Perlの慣用句で「開けるか死ぬか」程度の意味に読めます。- モード
- open関数の第2引数はモードです。
<
- 読出しモード
>
- 書込みモード
>>
- 追加書込みモード
- の3つがあります。
- 2引数呼出し
- 上のコードではopen関数を3つの引数で書きましたが、下記のように2個の引数でも書けます。
open($handle, "> testperl.txt" );
- と、ひとつの二重引用符の中にスペースで区切って書いても構いません。
- クローズ
- openで開いたファイルは、全ての操作が終わったら close 関数で閉じるます。
- 閉じ忘れるても、スクリプト終了時にインタープリターにより自動的に閉じられますが、明示的に閉じるとその時点でランタイムやオペレーションシステムのクローズ処理がはじまります。
- クローズはファイルハンドルを保持する変数がスコープを抜けたとき、より正確に言うとファイルハンドルへの参照がなくなったときに行なわれます。
- このためファイルハンドルは、my 宣言したレキシカルスコープの変数に保持するのが望ましいでしょう。
- ファイルハンドル
- open関数の第一引数(例では$handleの部分)は、ファイルハンドルです。
- 複数の入出力先を区別のためにファイルハンドルが必要になります。
- Perlにかぎらず、C言語など他の多くのプログラム言語でも、若干の記法の違いこそあるものの、ファイルハンドルのようなものが存在しており(CではファイルディスクリプタやFILE型へのポインタにほぼ相当)、このファイルハンドルと似たような使い方です。
- 書き込み命令の方法
- そして、書き込みをしたい場合、書き込みモードで開いたファイルに対し、
print ファイルハンドル名 "書き込みたい語句";
- で書き込みできます。
- たとえば上記コードの場合の
print $handle "zzzzz";
- なら、ファイルtestperl.txt に「zzzzz」と書き込まれます。
- 実際にコマンド端末で上記コード例を実行して試してみましょう。たしかにファイルに書き込まれているハズです。
- このような出力先を指定する方法でprint関数で外部ファイルに書き込みする方法は、Perlに特有の方法です。(C言語では、違う方法です。)
標準出力[編集]
たとえば、
- コード例
print STDOUT "qqq\n";
- をコマンド端末で実行すると、単に「qqq」と表示されます。(行末の \n は改行のエスケープシーケンス)
- STDOUT は、標準出力で、一般的にはコマンド端末画面のことです。
- print関数はこのように出力先を指定する機能があります。特に出力先を指定しない場合には、printの出力先は標準出力になるので、今までの単元では気にすることなく print "文字列" のように利用できたわけです。
ファイルハンドル[編集]
Perlには、次に挙げる特殊なファイルハンドルが組み込まれています。
- STDIN
- 標準入力を表します。
- STDOUT
- 標準出力を表します。
- STDERR
- 標準エラー出力を表します。
- DATA
- __END__以降を表します。
ファイルハンドルから一行ずつ読み込むには、< >
演算子を用います。
while (<STDIN>) { print; }
- これは次のコードと等価です。
while (defined($_ = readline *STDIN)) { print $_; }
- あるいは
print while <>;
- 空のファイルハンドルを指定すると標準入力から読み込みます。
- ただし、コマンドライン引数がある場合はそれをファイル名として解釈し、ファイルの内容を標準入力にパイプした上で、標準入力から読み込みます。
while (<>) { print; }
ファイルハンドルに対して出力するには、print()の間接ファイルハンドル記法を用います。
print STDOUT "Hello, world!\n";
ローカルファイルはopen()を呼び出してファイルハンドルに関連付けて操作します。
open my $fh, '<', '/etc/hosts' or die $!; print while <$fh>; close $fh;
グローバルスコープのスカラ変数でファイル名を与え、同名のファイルハンドルでファイルをオープンできます。
$FH = "/etc/hosts"; open FH; print while <FH>; close FH;
- 推奨できる書き方ではありませんが、過去に書かれたコードにこのパターンがある可能性はあるので、一つしか引数を取らないopen関数を見かけたら思い出してください。
コマンドラインオプション[編集]
コマンドライン引数は、@ARGVという特殊な配列に代入されます。サブルーチンの外で空引数のshift()を呼び出すと、shift(@ARGV)と解釈されます。
my $arg = shift; print "第一引数は $arg です。";
特殊変数$/[編集]
特殊変数$/を指定すると入力レコードレパレータを変更することができます(デフォルトは\n)。次の例では、「hoge.txt」から一行ずつではなくすべての内容を一度に読み出す。
open my $fh, '<', 'hoge.txt' or die $!; my $content = do { local $/; <$fh> }; close $fh;
正規表現[編集]
Perlは強力な 正規表現 をサポートしています。正規表現とは、大まかにいうと、検索の機能を高度化しやすくしたものです。Perl以外のJavaやJavaSciptやPHPなども正規表現をサポートしていますが、Perlは古くから正規表現を本格的にサポートしています。 また、Perlの拡張正規表現は、Perl Compatible Regular Expressions( PCRE ) としてPerlの外でも使うことができるため、正規表現のディファクトスタンダードの1つとなっています。
パターンマッチング[編集]
=~[編集]
二項演算子 =~
は、左辺のスカラー式を右辺のパターンマッチに拘束します。
正規表現に関する操作では、デフォルトで $_
という文字列を検索したり変更したりします。
この演算子は、そのような操作を他の文字列に対して行うようにします。
右辺は、検索パターン(//
)、置換(s///
)、または変換(tr///
)です。
左辺は、デフォルトの$_の代わりに検索、置換、または変換されるはずのものです。
スカラーコンテキストで使用する場合、返り値は通常操作の成功を表します。
リストコンテキストでの動作は、特定の演算子に依存します。
- 検索
if ("Wikibooks" =~ /book/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
- 書式
$検索対象の変数 =~ /検索したい文字列/
- 検索したい文字列を、変数が内部に含んでいるかどうかを調べる際に、
=~
および/
RE/
を使います。 - 上記のコードは真偽を返すので、主に条件分岐を行う際に用いられます。
!~[編集]
!~
は、=~
の論理反転バージョンです。
- コード例
if ("Wikibooks" !~ /books/) { print "Not match."; } else {