M.Hiroi's Home Page

Linux Programming

お気楽 Perl プログラミング超入門

[ PrevPage | Perl | NextPage ]

Perl 基礎知識 (前編)

Perl はC言語と同じく、手続き型のプログラミング言語です。プログラムの実行を制御する「文」、データを格納する「変数」、決められた処理を行う「関数」という構造に分かれます。

変数と関数は名前をつけて区別します。名前には、英数字とアンダースコア _ が使えます。英大文字と英小文字は区別されるので、FOO と Foo と fooは異なる名前と判断されます。関数は Perl にあらかじめ用意されている「組み込み関数」のほかに、私達ユーザーが定義することもできます。もちろん「再帰定義」も可能です。

●スカラーと変数

Perl で扱うことができる基本的なデータは、数値と文字列です。これを「スカラー」と呼びます。スカラーを格納する変数は先頭に $ をつけます。

my $名前;

Perl で変数を使う場合は my で宣言します。このとき、データの種類 (データ型) を宣言する必要はありません。数値と文字列どちらでも格納することができます。簡単な例を示しましょう。

my $n;
$n = 123;                # my $n = 123; でも OK
my $name;
$name = "M.Hiroi";       # my $name = "M.Hiroi" でも OK

Perl では # からその行の最後までがコメントになります。数値は、整数と実数 (浮動小数点数) を使うことができます。文字列は、ダブルクオート " で囲むか、シングルクオート ' で囲みます。ダブルクオートで囲んだ場合、Perl らしい機能が使えるのですが、これはあとで詳しく説明します。

変数に値をセットすることを「代入」といいます。 代入には = を使います。これはC言語や Java と同じですね。Perl では文の最後にセミコロン ; をつけます。これもC言語や Java と同じです。また、変数の宣言と同時に値を代入することもできます。

Perl はプログラムを実行するときに、文字列と数値の自動変換が行われる場合があります。次の例を見てください。

my $n = "123" + "456";

ご存じのように、+ は数値を加算する演算子です。このほかにも、お馴染みの演算子が使えます。

+ : 加算  $a = $a + 10;  ==>  $a += 10;
- : 減算  $a = $a - 10;  ==>  $a -= 10;
* : 乗算  $a = $a * 10;  ==>  $a *= 10;
/ : 除算  $a = $a / 10;  ==>  $a /= 10;
% : 剰余  $a = $a % 10;  ==>  $a %= 10;

このほかに、累乗 (べき乗) を計算する演算子 ** があります。また、C言語と同じく +=, -=, *=, /=, %= という書き方もできます。

"123" + "456" は、文字列を数値に変換してから足し算が行われるので、変数 $n の値は 579 となります。文字列の足し算だから 123456 となるわけではありません。逆に、文字列を連結する処理に数値を与えるとどうなるのでしょうか。次の例を見てください。

my $str = 123 . 456;

ピリオド ( . ) は文字列を連結する演算子です。この場合は、数値を文字列に変換してから連結が行われ、変数 $str の値は 123456 となります。

Perl は数値が必要な処理では文字列を数値に変換し、逆に文字列が必要な処理では数値を文字列に変換するのです。ほかの言語ではエラーとなるような処理でも、Perl は実行することができます。このことで、簡単にプログラムが組めるようになるのですが、データがどのように処理されるのか、きちんと理解しておかないと、思いもよらない結果にびっくりすることがあるかもしれません。

このほかに、複数個のスカラーを格納する「配列」や「連想配列」というデータがありますが、これらの説明は次回で詳しく行います。

●条件分岐

「条件分岐」と書くとなにやら難しい言葉のようにみえますが、プログラムにとっては最も基本的な動作のひとつです。簡単にいうと「もしも~~ならば○○をせよ」という動作です。


                       図 : 条件分岐

(1) では、「もしも条件を満たすならば、処理Aを実行する」となります。この場合、条件が成立しない場合は何も処理を実行しませんが、(2) のように、条件が成立しない場合でも処理を実行することができます。(2) の場合では、「もしも条件を満たすならば、処理Aを実行し、そうでなければ処理Bを実行する」となります。すなわち、条件によって処理Aか処理Bのどちらかが実行されることになります。

プログラミングの世界では、条件が成立することを「真 (true)」といい、条件が不成立のことを「偽 (false)」といいます。実際のプログラミングでは、true と false を表すデータが必要になります。true と false を表す専用のデータを用意するプログラミング言語もありますが、Perl の場合、スカラーを使って真偽を表します。まず、数値 0 は偽を表し、それ以外の数値は「真」となります。文字列の場合、空文字列 "" と "0" は偽を表し、それ以外の文字列は「真」と判断されます。"0" が偽なのは、数値に変換すると 0 になるからです。

条件分岐には if を使います。

リスト : if の構文

if (test) {
  処理A1;
   .....
  処理AZ;
} else {
  処理B1;
   .....
  処理BZ;
}

条件部 test を実行し、その結果が真であれば、処理A1 から処理AZ を実行します。{ } で囲まれた部分を「ブロック」と呼び、ここに複数の処理を書くことができます。test の結果が偽であれば、else から始まるブロックで書かれている処理B1 から処理BZ を実行します。 else ブロックは省略することができます。C言語では { } を省略できる場合がありますが、Perl の場合、必ず { } を書かないといけません。ご注意くださいませ。

もう少し複雑な使い方を紹介しましょう。

リスト : if ~ elsif ~ else の構文

if (test_A) {
  処理A;
} elsif (test_B) {
  処理B;
} else {
  処理C;
}

これを図に示すと次のようになります。


                      図 : 複雑な条件分岐

elsif を使うことで、if を連結することができます。test_A が偽の場合は、次の elsif の条件 test_B を実行します。この結果が真であれば処理B を実行します。そうでなければ、else ブロックの処理C を実行します。elsif はいくつでも繋げることができます。C言語では else if を使うのですが、Perl の elsifには驚きました。elseif や elif ではないので注意してください。

それから、C言語や Java でよく使われる条件分岐に switch 文がありますが、Perl ではサポートしていません。switch と同等なことを実現する方法もありますが、それは今後のお楽しみにとっておきましょう。

●比較演算子

ここで、数値と文字列を比較する演算子を紹介します。

表 : 比較演算子
数値文字列意味
==eq等しい
!=ne等しくない
<ltより小さい
>gtより大きい
<=leより小さいか等しい
>=geより大きいか等しい
<=>cmp小さければ -1, 等しければ 0, 大きければ +1

== と != はC言語と同じですね。最後の演算子 <=> と cmp が変わっています。C言語には文字列を比較する関数 strcmp が、比較結果を 負, 0, 正 で返します。このような結果を返した方が便利な場合もあるのです。このあたりは、C言語の影響を強く感じるところです。

Perl の場合、数値と文字列の自動変換が行われます。たとえば、文字列の比較に == を使うと、文字列を数値に変換してから比較するので、期待した結果にはならない場合があります。ほかの言語と違って、Perl ではエラーにはならないので注意してください。

●論理演算子

Perl の論理演算子を下表に示します。

表 : 論理演算子
操作意味
!x, not x x の否定(真偽の反転)
x && y, x and y x が真かつ y が真ならば真
x || y, x or y x が真まはた y が真ならば真

C言語と同じ演算子のほかに、not, and, or を使うことができます。not, and, or の優先順位は他の演算子よりも低いことに注意してください。&& (and) は左項が偽ならば右項を評価せずに偽を返します。|| (or) は左項が真ならば右項を評価せずに左項の値を返します。このため、&& と || は「短絡演算子」と呼ばれることもあります。

●三項演算子

Perl はC言語と同様な三項演算子 ? : を使うことができます。三項演算子の構文を示します。

条件式 ? 真の場合の式 : 偽の場合の式

簡単な例を示しましょう。

リスト : 三項演算子の例

// if 文
my $a;
if (条件式) {
  a = 式1;
} else {
  a = 式2;
}

// 三項演算子
my $a = 条件式 ? 式1 : 式2;

このように三項演算子を使うとプログラムを簡潔に記述できる場合があります。

●while 文と行入力演算子 <>

繰り返しは同じ処理を何度も行うことです。まずは簡単な繰り返しから紹介しましょう。while 文は条件が真のあいだ、ブロックに書かれている処理を繰り返し実行します。

while (条件部) { 処理A; 処理B; 処理C; }

          図 : while の処理

図を見ればおわかりのように、while 文はいたって単純です。C言語や Java でもお馴染みですね。繰り返しの途中で脱出するには、last を使います。これは、C言語や Java の break に相当します。このほかに、C言語や Java でお馴染みの for 文や csh で使われている foreach 文があります。これらの繰り返しは次回で詳しく説明しましょう。

ここで、はじめに で示したプログラム (cat.pl) に戻ります。

リスト : cat.pl

#! /usr/bin/perl

while (<>) { print; }

これはファイルの内容を表示するプログラムでした。print はデータを表示する関数です。while 文により print が繰り返し実行されるわけです。while 文の条件部 <> は、ファイルから 1 行読み込む「行入力演算子」です。ファイルを最後まで読み込んだ場合、<> は偽を返すので while 文の繰り返しが終了します。ファイル操作については、あとで詳しく説明します。

関数を呼び出す場合、名前のあとにカッコ ( ) を付けて、その中に引数を記述します。ただし、あらかじめ関数として宣言されている場合はカッコを省略することができます。print は組み込み関数として定義されているで、カッコを省略して呼び出すことができます。

ところで、読み込んだデータはどこにいったのでしょうか。実をいうと、while 文の条件部で <> が使われた場合に限り、データは $_ という変数に代入されます。$_ は「特殊変数」と呼ばれていて、Perl ではいろいろな特殊変数が用意されています。特に、$_ は陰の主役ともいえる変数で、多くの関数ではデータが明示されていないと、$_ に格納されているデータを処理するように動作します。つまり、print; は print $_; のことだったのです。これで、読み込んだファイルの内容を表示することができるのです。

Perl の特徴は、このような暗黙の動作が数多く定義されていることです。これらをうまく使うことで、プログラムを簡単に作れるようになっているのです。ですが、良いことばかりではありません。プログラムを見ただけでは、何をやっているかさっぱり理解できないことや、ときには思いもよらぬ動作を引き起こすこともあります。ここでは、$_ は重要な変数であることを覚えておいてください。

●use strict と use warnings

なお、最近の Perl ではファイルの先頭に use strict; と use warnings; を書くことが推奨されています。

リスト : use strict と use warnings

#! /usr/bin/perl
use strict;
use warnings;

while (<>) { print; }

実行結果は変わりませんが、これらの「おまじない」をつけると、文法を厳密にチェックしたり、ワーニング (警告) を表示してくれるので、間違いを見つけやすくなります。

●ファイルハンドル

最初に Perl はテキストファイルを処理するのが得意な言語、と説明しました。ファイルにアクセスするためのデータを Perl では「ファイルハンドル」と呼びます。Perl では、ファイルハンドルの指定が省略された場合、入力は標準入力から、出力は標準出力へ行われます。

一般に、「標準入力」はキーボードからの入力で、「標準出力」はデータを画面へ出力します。Perl では、あらかじめ標準入出力に対応するファイルハンドルが用意されています。

Perl ではファイルハンドルを英大文字で表すのが習慣です。STDIN が標準入力、STDOUT が標準出力、STDERR が標準エラー出力を表します。

ファイルハンドルは関数 open を使って生成します。

open IN, "<filename";   # ファイル filename をリードオープン
open OUT, ">filename";  # ファイル filename をライトオープン

第 1 引数が生成するファイルハンドルで、第 2 引数がファイル名です。ファイルハンドルには $ をつけないことに注意してください。最初はファイルからデータを読み込む場合です。ファイル名の先頭に < をつけるか、またはファイル名だけの場合は、入力用のファイルハンドルが生成されます。2 番目の例は、データ出力用のファイルハンドルを生成します。このとき、filename と同じ名前のファイルがあると、それを破壊するので注意してください。

最近の Perl は、open に 3 つの引数を渡すことができるようになりました。このとき、第 1 引数のファイルハンドルには変数を指定することができます。

my $file1 = "test.txt";
my $file2 = "test.out";
open my $in, "<", $file1;
open my $out, ">", $file2;

第 1 引数の変数にオープンしたファイルのファイルハンドルが格納されます。第 2 引数がファイルをオープンするモード (リードオープンやライトオープンなど) で、第 3 引数がファイル名になります。

ファイルを正常にオープンできた場合、open は 0 以外の値を返します。そうでなければ偽 (未定義値) を返します。Perl では open のエラーチェックを次のように行うことが多いようです。

open my $in  "<", "test.txt" or die "Can't open file test.txt";

die は引数の文字列を STDERR に出力してから、プログラムを異常終了します。終了コードは特殊変数 $! に格納されている値 (errno の値) になります。また、文字列 "..." の中に $! を含めると、errno に対応したエラーメッセージを得ることができます。

一般に、テキストファイルは行単位で処理を行う場合が多いです。Perl の場合、ファイルから 1 行読み込むには、行入力演算子 <> を使います。<> の中にファイルハンドル (または変数) を書くと、そのファイルから 1 行読み込みます。

<> はファイルハンドルを省略した書き方です。この場合、コマンドラインで指定されたファイルからデータを読み込みます。ファイル名が省略された場合は、標準入力からデータを読み込みます。したがって、cat.pl は次のように動作させることができます。

$ ./cat.pl < file1

file1 をリダイレクトさせても、ファイルの内容を表示できます。

print はデータを出力する関数ですが、ファイルハンドルの指定がない場合、標準出力 STDOUT に出力します。ファイルハンドルの指定は次のように行います。

print FILEHANDLE 引数

つまり、print; は print STDOUT $_; のことなのです。ただ、テキストファイルを処理する場合、結果は標準出力へ書き出して、ファイルへ保存する場合はリダイレクトすることが一般的です。このため、STDOUT を省略できるようになっています。なお、print の引数はカンマで区切って複数渡すこともできます。

open したファイルは必ず閉じましょう。close を使います。Perl のファイル処理は、open, while, <>, close を使うと次のようになるでしょう。

リスト : 典型的なファイル処理

open my $in, "<", "filename";
while (<$in>) {
    # $_ に対して処理を行う
}
close $in;

データの入力に <> を使えば、open, close も省略することができます。テキストファイルの処理では、それで十分な場合がほとんどでしょう。

簡単な例として、test.txt を test.out にコピーするプログラムを作ってみます。

リスト : ファイルのコピー (test00.pl)

use strict;
use warnings;

open my $in, "<", "test.txt";
open my $out, ">", "test.out";

while (<$in>) {
    print $out $_;
}

close $in;
close $out;

test.txt をリードモードでオープンし、test.out をライトモードでオープンします。test.txt のファイルハンドルは変数 $in に、test.out のファイルハンドルは変数 $out に格納されます。あとは while 文で $in からデータを読み込み、print で $out に出力するだけです。最後に close でオープンしたファイルをクローズします。

それでは実行してみましょう。

$ cat test.txt
  abc def ghi jkl
  def ghi jkl mno
  ghi jkl mno pqr
  jkl mno pqr stu
  mno pqr stu vwx
$ ls *.out
ls: *.out にアクセスできません: そのようなファイルやディレクトリはありません
$ perl test00.pl
$ ls test.out
test.out
$ cat test.out
  abc def ghi jkl
  def ghi jkl mno
  ghi jkl mno pqr
  jkl mno pqr stu
  mno pqr stu vwx

正常に動作していますね。

●文字列の変数展開

はじめに で示しましたが、cat.pl で行番号を付ける場合は次のようになります。

リスト : 行番号を付ける

#! /usr/bin/perl
use strict;
use warnings;

while (<>) { print "$.: $_"; }

$. は <> で読み込んだデータの行番号を表す特殊変数です。これで行番号をつけてファイルの内容を表示することができました。実は、" " の中で変数が使われていると、その値に置き換えた文字列を生成することができます。これを「変数展開」といいます。簡単な例を示しましょう。

my $name = "pen";
my $str1 = "This is a $name.";   # This is a pen. となる
my $str2 = 'This is a $name.';   # This is a $name. のまま

このほかに、お馴染みの \n (改行)や \t (タブ)を使うことができます。シングルクオート ' で囲まれた文字列は変数展開が行われないので、変数名 $name はそのまま文字列となり、\n や \t も 2 文字として扱われます。C言語であれば、関数 printf や sprintf を使わないといけませんが、それを文字列だけで表現できるのですから、とても便利な機能ですね。

今回はここまでです。次回は配列と連想配列について詳しく説明します。


初版 2015 年 4 月 5 日
改訂 2023 年 3 月 19 日

Copyright (C) 2015-2023 Makoto Hiroi
All rights reserved.

[ PrevPage | Perl | NextPage ]