perltrap - 不注意による Perl の罠
最も大きな罠とは、use warnings
あるいは -w スイッチを使うのを 忘れてしまうということです; warnings と "w" in perlrun を 参照してください。 二番目に大きな罠とは、あなたのプログラム全体を use strict
の元で 実行しないということです。 三番目の罠は、このバージョンの Perl での変更点を読まないということです; perldelta を参照してください。
awk に慣れた方は、以下のようなことに特に注意してください:
Perl のプログラムは、1 度だけ実行されます; 入力行毎ではありません。 -n
や -p
を使って暗黙のループを使えます。
Englishモジュールを
use English;
のようにしてロードすれば、awk でそうであったように ($/
のような)特殊変数を($RS のような)名前で参照することができます; 詳しくは perlvar を参照してください。
Perl では、すべての単純文(simple statement)の末尾にセミコロンが必要です (ブロックの最後に置かれたときを除きます)。 改行は文の区切りとはなりません。
if
や while
では中かっこが必要です。
Perl では、変数は "$" か "@" か "%" で始まります。
配列の添え字は 0 から始まります。 substr() や index() での文字列の位置も同様です。
配列の添え字が数値であるか、文字列であるかを決めなければなりません。
ハッシュ(連想配列)の値は、単に参照するだけでは存在することになりません。
比較を文字列によって行うのか、数値によって行うのかを 決めなければなりません。
入力を読み込むだけでは split は行われません。 配列への split は自分で行います。 また、split() 演算子の引数は awk のものと異なっています。
通常、カレント行は $0 ではなく $_ にあります。 一般的に、改行は取り除かれません。 ($0 には実行しているプログラムの名前があります)。 perlvar を参照してください。
$<digit> はフィールドを参照しません--これは直前に行った パターンマッチングの部分文字列を参照します。
print() 文は、$,
や $\
に値を設定しない限りフィールド区切り子や レコード区切り子を付加しません。 English モジュールを使っていれば、$OFS や $ORS に対して 設定することもできます。
ファイルに対して出力する前には、そのファイルをあらかじめオープンして おかなければなりません。
範囲演算子は ".." であって、カンマではありません。 カンマ演算子は C と同じような振る舞いをします。
マッチ演算子は "=~" であって、"~" ではありません。 ("~" はCと同様に、1 の補数を取る演算子です。)
べき乗の演算子は "**" であって、"^" ではありません。 "^" は C と同様、XOR 演算子です。 (awk が基本的に C と非互換であることにお気付きかもしれませんね。)
連接演算子は "." であって、空文字列ではありません。 (空文字列を使ってしまうと /pat/ /pat/
が、その 3 番目のスラッシュが 除算演算子と解釈されてしまうので正しく解析できなくなります-- Perl の字句解析器は "/", "?", ">" といった演算子に対して 多少文脈依存となっています。 実際、"." 自身も数値の始まりとなる可能性もあります。)
キーワード next
, exit
, continue
の振る舞いが異なります。
以下の変数の働きが異なります。
Awk Perl
ARGC scalar @ARGV (compare with $#ARGV)
ARGV[0] $0
FILENAME $ARGV
FNR $. - something
FS (whatever you like)
NF $#Fld, or some such
NR $.
OFMT $#
OFS $,
ORS $\
RLENGTH length($&)
RS $/
RSTART length($`)
SUBSEP $;
$RS に正規表現をセットすることはできません; できるのは文字列だけです。
妙だと思ったときには awk の構文を a2p に通して、出力されたものを 見てみましょう。
知的な C と C++ のプログラマは以下のことに注意すべきです:
if
や while
には中かっこが必要です。
else if
ではなく、elsif
を使わなければなりません。
C の break
と continue
は、Perl ではそれぞれ last
と next
となります。 C とは異なり、これらは do { } while
構文では 使えません。 "Loop Control" in perlsyn を参照してください。
switch 文は given
/when
と呼ばれ、perl 5.10 以降でのみ利用可能です。 "Switch Statements" in perlsyn を参照してください。
Perl では、変数は "$" か "@" か "%" で始まります。
コメントの始まりは、"#" であり、"/*" や "//" ではありません。 Perl は C/C++ のコメントを除算演算子、終端していない正規表現、 定義性和演算子として解釈するかもしれません。
なにかのアドレスを得ることはできません; Perl には似たような演算子である バックスラッシュがありますが、これはリファレンスを生成します。
ARGV
は大文字でなければなりません。 $ARGV[0]
が C での argv[1]
に相当し、argv[0]
にあたるものは $0
です。
link(), unlink(), rename() などのシステムコールは、成功時に 0 ではなく非 0 の値を返します。 (但し、system() は成功時に 0 を返します。)
シグナルハンドラは、シグナル番号ではなくシグナル名を扱います。 使用できるシグナル名は、kill -l として確かめてください。
思慮深い JavaScript プログラマは以下のことに注意すべきです:
Perl では、二項の +
は常に加算です。 $string1 + $string2
は両方の文字列を数値に変換してから加算します。 二つの文字列を結合するには、.
演算子を使ってください。
+
単項演算子は Perl では何もしません。 これは文法的な曖昧さを避けるために存在しています。
for...in
と異なり、Perl の for
(foreach
と書くこともあります) は 左側に任意の式を置くことはできません。 これは変数でなければなりません:
for my $variable (keys %hash) {
...
}
さらに、ここで keys
を忘れないでください; foreach my $kv (%hash) {}
は キーと値に対して反復するので、一般的には有用ではありません ($kv はキーになり、 次に値になり、という形になります)。
配列のインデックスに対して反復するには、 foreach my $i (0 .. $#array) {}
を使ってください。 foreach my $v (@array) {}
は値に対して反復します。
Perl は if
, while
, foreach
などに引き続いて中かっこが必要です。
Perl では、else if
は elsif
と書きます。
? :
は代入より高い優先順位を持ちます。 JavaScript では、以下のように書けて:
condition ? do_something() : variable = 3
条件が偽の場合にのみ変数に代入されます。 Perl では、かっこが必要です:
$condition ? do_something() : ($variable = 3);
または単に if
を使ってください。
Perl は文の分割にセミコロンが必要です。
my
で宣言された変数は宣言の 後 でのみ効果を持ちます。 $x = 1; my $x;
と書いて最初の代入が同じ変数に影響すると 想定することはできません。 これは外側のスコープ、あるいはグローバル変数の $x
に代入されます。
また、変数は次の 文 まで有効にならないことにも注意してください。 これは、my $x = 1 + $x
とすると 2 番目の $x は前に宣言されたものを 参照するということです。
my
変数のスコープは現在の関数ではなく現在のブロックです。 {my $x;} $x;
と書くと、2 番目の $x
はブロックの内側で宣言された変数を 参照できません。
オブジェクトのメンバは変数としてアクセスできません。 with(object) { method() }
の Perl での一番近い等価物は for
で、 これは $_
がオブジェクトへの別名となります:
for ($object) {
$_->method;
}
メソッドが呼び出されたオブジェクトまたはクラスは、独立した this
値ではなく メソッドの引数の一つとして渡されます。
熟練した sed プログラマは以下のことに注意すべきです:
Perl のプログラムは、1 度だけ実行されます; 入力行毎ではありません。 -n
や -p
を使って暗黙のループを使えます。
置換における後方参照には、"\" ではなく "$" を使います。
"(", ")", "|" といったパターンマッチのメタキャラクタは、その直前に バックスラッシュを置く必要はありません。
範囲演算子は ...
であって、カンマではありません。
鋭いシェルプログラマは以下のことに注意すべきです:
バッククォート演算子は、コマンド内にシングルクォートがあっても 変数の展開を行ないます。
バッククォート演算子は csh とは違って、返された値を変換しません。
シェル (特に csh) は、コマンドラインごとに何段階もの置換を行ないます。 Perl はダブルクォート、バッククォート、山かっこ、検索パターンといった 特定の構造でだけ置換を行ないます。
シェルは一度に少しずつ解釈を行ないます。 Perl は実行前にプログラム全体をコンパイルします (コンパイル時に実行される BEGIN
ブロックを除く)。
引数は $1, $2 などではなく、@ARGV から得られます。
環境変数は、自動的には独立したスカラ変数として利用できるようになりません。
シェルの test
は "=", "!=", "<" などを文字列比較に使い、"-eq", "-ne", "-lt" などを数値比較に使います。 これは Perl とは逆です; Perl では eq
, ne
, lt
を文字列比較に使い、 ==
, !=
<
などを数値比較に使います。
実践的な Perl プログラマは以下のことに注意すべきです:
多くの演算子がリストコンテキストとスカラコンテキストとで 振る舞いが変わることを忘れないでください。 詳しくは perldata を参照してください。
裸の単語、特に全てが小文字のものはできる限り使わないでください。 見た目だけではその「裸の単語」が関数なのか、 文字列なのかが判断できません。 文字列にはクォートを、関数呼び出しには括弧をつければ、 迷うこともないでしょう。
組込み関数のどれが(chop() や chdir())のような単項演算子で、 どれが(print() や unlink())のような リスト演算子であるかは見ただけではわかりません。 (プロトタイプがなければ、ユーザー定義サブルーチンは リスト演算子として のみ 定義でき、単項演算子にはできません。) perlop と perlsub を参照してください。
いくつかの関数が $_ や @ARGV などをデフォルトにしていますが、 同じことを期待する他の関数がデフォルトになっていないことを覚えるのに、 辛いタイピングが必要でしょう。
<FH> 構造はファイルハンドルではなく、そのハンドルに対する行読み込みの 操作(readline operation)です。 while ループの条件式の中にこのファイル読み込みだけがあった場合には 読み込まれたデータは $_ に代入されます。
while (<FH>) { }
while (defined($_ = <FH>)) { }..
<FH>; # data discarded!
=~
が必要なところで =
を使わない、ということを忘れないでください; これら二つの構造はかなり違います:
$x = /foo/;
$x =~ /foo/;
do {}
構造は、ループ制御を行えるような本当のループではありません。
ローカル変数は、my()
で済むところではこれで済ませてください (使えない場所については、perlform を参照してください)。 local()
を使えばグローバル変数に対するローカルな値を与えますが、 動的スコープの不慮の副作用の可能性は、そのままです。
モジュールにある export された変数を局所化すると、その export された 値は変更されません。 ローカル名は新しい値の別名(alias)となりますが、 外部名は元々の値の別名のままです。
いつものように、バグとして公式に宣言されたものがあれば、 それは修正されて取り除かれるでしょう。