Go to the previous, next section.

データの型とオブジェクト

データの型・コンテキスト

perl には 3 種類のデータ型 : スカラー、スカラー配列、および連想配列がある。 通常の配列は添え字が数字だが、連想配列の場合は文字列である。

perl における演算や値の解釈は、 演算や値のコンテキストからの要求に依存することがある。 主なコンテキストには 3 つ : 文字列、数値、および配列がある。 演算の中には、配列を要求するコンテキストでは配列を、 そうでなければスカラー値を返すものがある。 (そのような演算子についてはそのドキュメントに記述されている。) スカラー値を返す演算子は、 コンテキストが文字列あるいは数値のどちらを要求しているかは考慮しないが、 スカラー変数およびスカラー値は 文字列あるいは数値のコンテキストのふさわしい方に解釈される。 スカラーはそれがヌル文字列あるいは 0 でなければ論理的に真であると解釈される。 演算子が返す論理値は真の場合は 1、 偽の場合は 0 または '' (ヌル文字列)である。

実は、ヌル文字列には 2 種類ある。 define されたもの、undefined のものである。 undefined のヌル文字列はエラーや、end of file や、 初期化されていない変数や配列要素を参照しようとした時など、 実際の値が存在しない時に返る。 undefined ヌル文字列は最初にそれにアクセスすることにより、 defined になることがあるが、その前に defined() 演算子を用いて 値が defined かそうでないかを知ることができる。

スカラー変数への参照は、それが配列の一部であっても、 常に `$' で始める。すなわち、以下の通りである。

$days            # 単純なスカラー変数
$days[28]        # 配列 @days の 29 番目の要素
$days{'Feb'}     # 連想配列の値の一つ
$#days           # 配列 @days の最後の添え字

しかし、配列全部や一部の取り出しなどは '@' で始める。

@days	        # ($days[0], $days[1],... $days[n])
@days[3,4,5]  # @days[3..5] と同じ
@days{a,c}    # ($days{'a'},$days{'c'}) と同じ

そして連想配列全部を扱うには、'%' で始める。

%days		# (key1, val1, key2, val2 ...)

これら 8 つはすべて左辺値として扱うことができる。すなわち、代入可能である。 (さらに、あるコンテキストでは代入操作自体も左辺値となりうる。 str および chop における例を参照のこと。)

See section s/パターン/置き換え/,
See section tr/検索リスト/置換リスト/, and See section chop.

スカラーへの代入を行うと、右辺をスカラーのコンテキストで評価するのに対し、 配列や配列の一部への代入は右辺を配列のコンテキストで評価する。

配列 @days の長さを、csh のように、 `$#days' で評価することができる(実際には、配列の長さではなく、 最後の要素の添え字である。なぜなら、通常 0 番目の要素があるからである)。

$#days へ代入すると、配列の長さが変わる。 この方法により配列を小さくしても、実際には値は何も破壊されない。 すでに小さくした配列を大きくすると、もともとあった要素が元に戻る。

また、大きくなりそうな配列をあらかじめ大きくしておくと、 効率をいくらか良くすることができる。(配列を大きくするには、 配列の最後を超える要素に代入を行う方法もある。この方法と、 $#whatever へ代入する方法との違いは、 間の要素にヌルがセットされることである。)

配列の中身を捨てて空にするには、ヌルリスト () を代入すれば良い。 次の二つは全く同等である。

@whatever = ();
$#whatever = $[ - 1;

配列をスカラーのコンテキストで評価すると、配列の長さが返る。 次の式は常に真である。

scalar(@whatever) == $#whatever - $[ + 1;

連想配列をスカラーのコンテキストで評価すると、 配列が要素を含む場合かつその場合に限り真の値を返す。 (要素がある場合に返る値は文字列で、 使用している bucket の数およびアロケートされている bucket の数からなり、 スラッシュで区切られている。)

多次元配列は直接はサポートしていないが、 連想配列を用いて 複数の添え字をエミュレートする方法については $; 変数の項を参照のこと。 また、多次元の添え字を 1 次元の添え字に変換するサブルーチンを書くこともできる。 See section $; : 多次元配列エミュレーションの際の添え字の区切り.

各々のデータ型に応じて、それぞれの名前空間がある。 衝突を心配することなく、同じ名前をスカラー変数、配列、連想配列、 ファイルハンドル、サブルーチン名、またはラベルにつけることができる。

変数や配列への参照は常に $@% で始まるので、 予約語は変数名については実際には使用可能である。 (しかし、ラベルやファイルハンドルについては予約語は使用できない。 特殊な文字で始まらないからである。 ヒント: `open(log,'logfile')' より `open(LOG,'logfile')' を 使った方が良い。 大文字のファイルハンドル名を使うと、読み易さも向上し、 将来予約される単語との衝突も避けることができる。)

大文字小文字の区別は重要である -- `FOO'`Foo'`foo' は すべて異なる名前である。アルファベットで始まる名前は数字や下線を含んでもよい。 アルファベットで始まらない名前は 1 文字に限られる。 例: `$%'`$$'。 (ほとんどの一文字名は perl の予約変数として意味がある。 Predefined Names の項を参照。See section 予約変数).

文字列の扱い

数値文字列は通常の小数点や整数の形式で表す。

12345
12345.67
.23E-10
0xffff	# 16 進
0377	#  8 進

文字列はシングルクォートまたはダブルクォートで区切られる。 これらはシェルにおけるクォートとよく似ている。 ダブルクォートで囲まれた文字列にはバックスラッシュや変数の置換が行われる。 シングルクォートで囲まれた文字列には行われない。( \' と \\ を除いて。)

通常のバックスラッシュ規則が改行やタブなどの文字を表すのに使える。 加えて以下のちょっと変わった形式も使える。

\t      タブ
\n      改行
\r      リターン
\f      フォームフィード
\b      バックスペース
\a      アラーム(ベル)
\e      エスケープ
\033    8 進文字
\x1b    16 進文字
\c[     コントロール文字
\l      次の文字を小文字にする
\u      次の文字を大文字にする
\L      \E までを小文字にする
\U      \E までを大文字にする
\E      大小文字の修飾の終り

改行を直接文字列に書き入れることもできる。 すなわち、文字列は始まった行と異なる行で終わることができる。 これは便利であるが、最後にクォートを忘れると、 クォートを含むかなり離れた別の行を見つけるまで perl は エラーを報告しないだろう。

文字列内の変数置換はスカラー変数・通常の配列値・配列の一部に限られる。 (言い換えると、$@ で始まる識別子と、 それに括弧で囲まれた添え字がある場合だけである。) 次のコードは `The price is $100.' を出力する。

$Price = '$100'; # 解釈されない
print "The price is $Price.\n";# 解釈される

注意:
後に続くアルファベットや数字と区別するために、 識別子を {} で囲うことができる。 また、シングルクォートで囲まれた文字列は その前の単語とはスペースで区切らなければならない。 なぜなら、シングルクォートは識別子として有効な文字だからである。 (Packages の項を参照。See section パッケージ.)

特殊な文字列が二つあり、__LINE____FILE__ である。 これはプログラムのその時点での行番号とファイル名を表す。 これらは独立したトークンとしてのみ使用できる。 文字列中に書き入れることはできない。

さらに、__END__ は実際のファイルの終了の前の スクリプトの論理的な終了を示すのに使える。 残りのテキストは全て無視される (ただしファイルハンドル DATA から読むことができる。)。 ^D^Z の 二つのコントロールキャラクタは __END__ と同じ意味である。

文法的に解釈不可能な単語は それがシングルクォートで囲まれているかのように扱われる。 このため、アルファベット・数字・下線のみからなる単語は アルファベットで始まらなければならない。 ファイルハンドルやラベルと同じく、小文字のみからなる裸の単語は 将来の予約語と衝突する危険がある。-w スイッチを使えば、 perl はそのような単語について警告する。

配列値をダブルクォートで囲まれた文字列に入れた場合は、 配列の全要素を $" で示される区切り(デフォルトはスペース) で区切って一つにした文字列になる。 (3.0 以前のバージョンの perl では @ は メタキャラクターではなかったので、 @array$array[EXPR]@array[LIST]$array{EXPR}@array{LIST} の解釈は プログラムのどこかで参照されているか、 予め define されている場合にのみ行われる。) 次の二つは同等である。See section $” : 配列値を ”” で囲んだ時に要素間に入るセパレータ for $".

$temp = join($",@ARGV);
system "echo $temp";

system "echo @ARGV";

検索パターン(これにもダブルクォートと同じ置換が行われる)においては、 あいまいな場合がある。

/$foo[bar]/
/${foo}[bar]/ ([bar] は正規表現の文字クラス)
として解釈するべきか、
/${foo[bar]}/ ([bar] は配列 @foo の添え字)
として解釈するべきか ?

@foo が存在しないならば、明らかに文字クラスである。 @foo が存在すれば、perl は [bar] についてよく考え、 その答えはほとんどの場合正しい。もし間違った解釈をしたり、 あるいはあなたが単に偏執狂ならば、 上で述べたように {} を入れることで正しい解釈をさせることができる。

行指向の引用法

行指向の引用法はシェルの同様の文法に基づいている。 << の後に引用文の終わりを示す文字列を指定すると、 現在行からその文字列が現れるまでの行全てがその値になる。 終わりを示す文字列は識別子でも、引用するテキストでもよい。 引用するテキストの場合、通常のクォーティングと同じく クォートの種類がテキストの扱い方を決める。 クォートしない識別子はダブルクォートと同じように働く。 (スペースを入れた場合、それはヌル識別子として扱われ、これは有効で、 最初のブランクラインにマッチする。--- 下の Merry Christmas の例を見よ。) 終わりを示す文字列はそれだけで(クォートやスペースを回りにつけず) 存在しなければならない。

     print <<EOF;        # 前の例と同じ
The price is $Price.
EOF

     print <<"EOF";      # 上の例と同じ
The price is $Price.
EOF

     print << x 10;      # ヌル識別子が終わりを示す文字列
Merry Christmas!

     print <<`EOC`;      # コマンドを実行する
echo hi there
echo lo there
EOC

     print <<foo, <<bar; # スタックに積むことができる
I said foo.
foo
I said bar.
bar

配列の表現

配列の表現は、個々の値をコンマで区切り、括弧 () で囲む:

(LIST)

配列値を要求しないコンテキストでは、C のコンマ演算子と同じく、 最後の要素の値が配列表現の値となる。例えば、

@foo = ('cc', '-E', $bar);

は配列 foo に全配列値を代入するが、

$foo = ('cc', '-E', $bar);

は変数 bar の値を変数 foo に代入する。

注意: 変数として存在する(actual)配列のスカラーのコンテキストにおける値は 配列の長さである。次の例では $foo に 3 を代入する。

@foo = ('cc', '-E', $bar);
$foo = @foo;		# $foo は 3 になる

配列表現の括弧を閉じる前に余分なコンマがあっても良い。 つまり、以下の表現は可能である。

@foo = (
  1,
  2,
  3,
);

リストが評価される時は、 リストの要素はすべて配列のコンテキストで評価され、結果として得られる配列値は、 個々の要素がリストのメンバーであったかのようにリストに入れられる。 つまり、配列はリストにおいては区別がなくなる。リスト

        (@foo,@bar,&SomeSub)

@foo, @bar の全要素 および SomeSub という名前のサブルーチンが返す全要素を含む。

リストの値は通常の配列と同様に添え字をつけて指定できる。

$time = (stat($file))[8];	# stat は配列値を返す
$digit = ('a','b','c','d','e','f')[$digit-10];
return (pop(@foo),pop(@foo))[0];

配列のリストはその要素が全て左辺値であり、 かつその時にかぎり代入可能である。

($a, $b, $c) = (1, 2, 3);

($map{'red'}, $map{'blue'}, $map{'green'}) = (0x00f, 0x0f0, 0xf00);

最後の要素は配列又は連想配列であってもよい。

        ($a, $b, @rest) = split;
        local($a, $b, %rest) = @_;

実際にはリストのどこに配列を入れてもいいのだが、 リスト中の最初の配列が全ての値を取ってしまい、 その後の要素にはヌル値が入ってしまう。 これは local() において便利かもしれない。(See section local.)

連想配列の表現は、キー、値として解釈されるべき値のペアを含む。

# 上記の map への代入と同じ。
%map = ('red',0x00f,'blue',0x0f0,'green',0xf00);

スカラーのコンテキストでの配列の代入は 代入の右辺の expression により得られる要素の数を返す。

$x = (($foo,$bar) = (3,2,1)); # $x を 2 ではなく 3 にセットする

コマンドの出力

文字列を ` ` で囲んだ場合、 まずダブルクォートと全く同じ変数置換が行われる。次にシェルの場合と同じく、 コマンドであると解釈され、そのコマンドの出力がこの擬似表現の値となる。

スカラーのコンテキストでは、全出力が入った 1 つの文字列が返る。

配列のコンテキストでは、出力の 1 行を 1 要素とした配列値が返る。 (他の行ターミネータを使う場合には $/ をセットする。)See section $/ : 入力レコードのセパレータ.

コマンドは擬似表現が評価されるたびに実行される。 コマンドのステータスは $? に返る。(See section $? : パイプのクローズ、system 関数などで返ったステータス.)

csh の場合とは異なり、返ってくるデータには置換は一切行われない。--- 改行は改行のままである。どのシェルとも異なり、 シングルクォートで囲んでもコマンド内の変数名は変換されてしまう。 $ をシェルに渡すには、バックスラッシュを使う必要がある。

ファイルハンドル/ファイル名置換

<> で囲んだファイルハンドルを評価すると、 そのファイルから次の行を読み込む (改行を含むので、EOF までは偽にならない。 このときは値として undefined が返る)。 通常はその値を変数に代入する必要があるが、 一つだけ自動的に代入が行われる状況がある。 <ファイルハンドル> のみが while ループの条件である場合は、 (そしてこの場合にかぎり)値は変数 `$_' に自動的に代入される。 (奇妙に思うかも知れないが、 これをほとんどの perl スクリプトにおいて使うであろう。) とにかく、次の例は全て同等である。

while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while $_ = <STDIN>;
print while <STDIN>;

ファイルハンドル STDINSTDOUTSTDERR は 予約されている。(stdinstdoutstderr でも動作するが、 パッケージの中ではグローバルではなくローカルな識別子として解釈されるので、 働かない。)

これら以外のファイルハンドルは open 関数を用いて作成する。 (See section open.)

<ファイルハンドル> を配列を要求するコンテキストで用いると、 全入力行の 1 行がそれぞれ 1 要素となる配列が返る。 この方法を使うと簡単に巨大なデータ空間を作ることができるので、 注意して使った方がいい。

ヌルファイルハンドル <> は特殊で、 sed や awk の動作をエミュレートするのに用いる。 <> には、標準入力か、 またはコマンドラインにリストアップした全ファイルから入力される。 これは次のように動作する。

<> を最初に評価すると、配列 ARGV がチェックされ、 ヌルであれば、$ARGV[0]`-' にセットされる。 これは、オープンする時に標準入力となる。 次に配列 ARGV がファイル名のリストとして処理される。次のループ

while (<>) {
     ...            # 各行に対するコード
}

は下と同等である。

unshift(@ARGV, '-') if $#ARGV < $[;
while ($ARGV = shift) {
     open(ARGV, $ARGV);
     while (<ARGV>) {
          ...      # 各行に対するコード
     }
}

違いは、前者は後者ほど書くのが面倒でないということだけであり、 前者でも実際に配列 ARGV をシフトし、 現在のファイル名を $ARGV に代入している。 また、ファイルハンドル ARGV を内部で用いている。

1 番目のファイル名を配列の最初に残しておくかぎり、 最初の <> の前で @ARGV に手を加えることができる。 行番号 ($.) は入力が一つの大きなファイルであるのと同じく、 継続して増える。 (ファイル毎に行番号をリセットする方法については eof の例を参照のこと。 See section eof.)

@ARGV にファイルのリストをセットしたい場合は、そうすればよい。 スクリプトにスイッチを渡したい場合は、 最初に次のようなループを入れればよい。

while ($_ = $ARGV[0], /^-/) {
     shift;
    last if /^--$/;
     /^-D(.*)/ && ($debug = $1);
     /^-v/ && $verbose++;
     ...       # ほかのスイッチ
}
while (<>) {
     ...       # 各行に対するコード
}

<> は一度だけ偽を返す。この後もう一度呼ぶと、 新たな @ARGV リストの処理を行っているものと見なす。 そしてこの時 @ARGV を セットしていない場合は STDIN から入力される。

<> の中の文字列がスカラー変数を参照している場合 (例えば <$foo>)、その変数は 入力が行われるべきファイルハンドルの名前を値として持つ。

<> の中の文字列がファイルハンドルでない場合は、 置換されるべきファイル名パターンであると解釈され、 コンテキストによりファイル名の配列またはリスト内の次のファイル名が返る。 1 レベルの $ の解釈は最初になされるが、 上で述べたように <$foo> は 間接的にファイルハンドルを指すので使えない。 強制的にファイル名置換と解釈させるためには、 {} を入れればよい: <${foo}>

while (<*.c>) {
     chmod 0644, $_;
}

は次と同等である。

open(foo, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|");
while (<foo>) {
     chop;
     chmod 0644, $_;
}

実は、現在の所、後者の方法でインプリメントしている。 (つまり、マシン上に `/bin/csh' がないかぎり スペースなどを含むファイル名についてはうまく働かない。) もちろん、上の操作を行う最も短い方法は

chmod 0644, <*.c>;

である。

Go to the previous, next section.