Perl v5 自分用メモ
とかくperlは書き方が自由すぎる。いちいち調べていたら、小さなプログラムでも書くのに時間がかかる。また、はまるポイントも色々ある。
そのため、ここに文法と注意点をまとめます。自分のメイン言語がJavaのため、たまに比較します。
言語としては「Perl」、実行プログラムとしては「perl」として、この記事を書いたつもりです。また、「変数」とだけ書いてある場合は、大抵スカラー変数のことです。
実行環境のperl
v5.18.2
TL;DR
- メモです
- 今更ですがv5のPerlです
- Nothing new here
言語思想
実用性と多様性
コメント
- 単一行コメント(#)
# This is a comment
さすがUNIX上での作業が発端となった言語、シェルスクリプトと同じですね。 - 複数行コメント(=pod / =cut)
=pod
multi-line comments
=cut
- カッコで囲っても囲わなくても良い。
print "hello\n";
print ("hello\n");
- printの直後にカッコがあると閉じタグでその行の解釈が終わる。
print (2 * 3) /2 ; # 結果は6
print (2 * 3 / 2); # 結果は3
print 2 * 3 / 2 ; # 結果は3
累乗計算
** 演算子が使える。
print 2 ** 3 ; # 8
JavaならMath.pow(2.0, 3.0)ですね。
正の平方根を返すsqrt()関数はPerlにもある。というか、Perlの方がJavaより古い。(Wikipedia調べ、Perl=1987/Java=1995)
ワンライナー
-eをつけて実行
perl -e 'print 2 ** 3;' # 8
桁が大きな数の、科学技術表記が可能
エクセルみたいに、「1e+200」という表記ができる
「1e+200」は、10の200乗です。
インクリメントは前置・後置ともに実行可能
複数変数への同時代入の仕方
perl -e '$a = $b = $c = 5; print "$a $b $c\n";' # 結果:5 5 5
Javaだとこう書けない。int a = 5, b = 5 , c = 5; となる。
おまじない
use strict;
use warnings;
- strict
変数などを使う前に宣言を必要とする - warnings
初期化していない変数にアクセスした場合などに警告を出す
チェックする内容としては、perl -wオプションと変わらないみたですが、use warningsの場合は、記述したファイルに適用範囲が限定されるみたです。また、use strict "vars"; やuse strict;
no strict "vars"; のように適用する対象を分けることもできる。 - プラグマ(pragma)
strictやwarningsなどはPerlプラグマと呼ばれる、機能拡張モジュールです。小文字でプラグマ名を書く慣習らしいです。
参照:PerlPlus 厳密な構文チェック
perldoc.jp 5.12.3 strict
Perl/ライブラリ・モジュールとオブジェクト指向
文字列結合
. (ピリオド、ドット)で結合する。複合代入演算子としても使える。(.=)
Javaは+, Excel関数だと&ですか。
Perlは動的に変数の型を決める(というか数値も文字列も許容する)ので、. と + で色々使い分けることが可能です。
$a = "a" ; $b = "b"; $one = 1; $two = 2;
print $a . $b; # ab
print $a + $b; # 0
print $one + $two; # 3
print $one . $two; # 12
undef
use warnings使っていればお目にかからないとは思いますが、初期化されていない変数に設定されている値です。
undefの取り扱い
- 数値としてみた場合は0としてふるまい
- 文字列としてみた場合は""としてふるまう
(引用元:すぐわかるPerl 47P)
判定式・条件式
Perlには真偽値という型はないらしく、次のコードのifブロックは実行されます。
if ( false ) {
print "実行されます\n";
}
Perlで偽と判定される文字列や数値
- undef
- "" (空文字)
- "0" (文字列のゼロ)
- 0 (数値のゼロ)
文字列の一致はeq , 数値の一致は==
シェルスクリプトと混ぜるな危険!
シェルスクリプトだと、eq,ne,gt,lt,ge,leを数値比較に使います。
一方、Perlはeq,ne,gt,lt,ge,leを文字列比較に使い、数値比較には、==,!=,<,>,<=,>=を使います。
if ~ elsif ~ else
各言語によって、else ifだったりelsifだったりしますが、Perlはelsifです。
馴染みのある言語のif ~ elsif ~ else
Lang | State |
---|---|
Perl | if (条件式1) {~;} elsif (条件式2) {~;} else {~;} |
Java | if (条件式1) {~;} else if (条件式2) {~;} else {~;} |
bash | if 条件式1 ; then ~ ; elif 条件式2 ; then ~ ; else ~ ; fi |
Excel VBA | If 条件式1 Then 〜 ElseIf 条件式2 Then 〜 Else ~ End If |
Python | if 条件式1: タブ~ elif 条件式2: タブ~ else: タブ~ |
※ Mac OS用のExcel持っていないのでおうちで試せてませんが、Excel VBAは改行が必要な気がします。
※ 左詰めした表の中にスペースが入らないので、苦肉の「タブ」
unless
英語の意味のとおり、「〜しない・〜でない限り」実行するブロック。つまり、条件式が偽の時に実行される。elseブロックを追加できて、unlessのelseブロックは条件式が真の時に実行される。
参照:PerlPlus unless文
unless ( 2 == 1 ) { print "unless"; } # こちらが実行されます
else { print "unless else" }
if ( 2 == 1 ) { print "if"; }
else { print "if else"; } # こちらが実行されます
多分、他言語では実装されていないことが多いので、チームでの読みやすさを考慮するとunlessは書かないほうがいのかなと感じました。ifのelseブロックを使うか、ifの条件式を反転(!)させることで代用できるので、unlessである必要性はない。まぁ、好み・宗教問題ですね。
if ( ! (2 == 1) ) { print "if"; } # こちらが実行されます
else { print "if else"; }
※ !==より優先順位が高いので、は(2==1)というように()でくくらないと判定式を反転できない
※ (追記)notは==より優先順位が低いので、()で囲う必要がない
Pythonだとif notでunlessと同じことができるみたいです。
(参照:Chat-blog 【python】unlessがないのでnotを使う)
論理演算子
& <=> &&, | <=> || の描きわけで、短絡評価するかどうかを書き分けることが可能。
&&, || は短絡評価(ショートカット)するので、true/falseを判定した時点で、もし右側に判定式が続いてても評価しない。Javaと同じ。
論理演算子の種類
上にあるほうが評価の優先順位が高い。
結合方向 | 演算子 |
---|---|
左結合 | 項(丸括弧で囲った部分) リスト演算子 (左方向に対して) |
右結合 | ! |
非結合 | == != <=> eq ne cmp |
左結合 | & |
左結合 | | ^ |
左結合 | && |
左結合 | || |
右結合 | = += -= *= などの代入演算子 |
右結合 | not |
左結合 | and |
左結合 | or xor |
デフォルト値を設定する
結論からすると、defined関数を使って、undefかどうかでデフォルト値を設定しましょう。
$result = defined $results{$name} ? $results{$name} : "not taken" ;
参照:blog 20100901 / Perl 「 論理演算子 」論理 OR を利用したデフォルト値の設定とその問題点 (0x8c)
公式ドキュメント日本語訳に下記のような例が載っていました。
$a = $b || $c;
引用:論理和と排他論理和
=(代入演算子)より||の方が評価優先順位が高いので、$bまたは$cの結果を$aに代入できます。||と=でもデフォルト値を設定することがように見えますが、$bが下記の値の場合、予期せず$cが評価される場合があるみたいです。
- "" (空文字)
- "0" (文字列のゼロ)
- 0 (数値のゼロ)
or die
die関数はプログラムを終了させる関数で、orは上記にもある論理演算子です。
ファイルのオープン時に組み合わせます。
こちらの記事になぜ「||」ではいけないかがわかりやすく説明されています。
while
while ( 条件式 ) { 処理 }
- last;でループを抜けることができる
foreach
foreach $val ( @array ) { $valを使った処理; }
Javaとは違うのだよ、Javaとは。
for (データ型 変数名: コレクション) { 変数を使った処理; }
コアダンプ
coreという名前のファイルを出力しプログラムが異常終了すること。
メソッド(関数)一覧
メソッド名 | 動作 | 使い方 |
---|---|---|
数値や文字列を出力する | print "hogehoge"; | |
last | ループブロックの終了 | last; |
defined | 引数がundefの場合、偽を返す | $result = defined $results{$name} ? $results{$name} : "not taken" ; |
die | プログラムを終了させる | リストを引数に取る 改行でdie関数が終わらない場合は、エラー位置を示すエラーメッセジが挿入される |
eval | 引数をperlで一度処理する {}で囲うと一度変換する ※実行と変換は違う |
eval 1+3; # 4 $temp = "1+2"; eval $temp; # 3 eval { $temp }; # 1+2 |
リスト
- リスト=()で囲んだ複数の値を持つブロック ※ カンマ区切り
- リストを用いることで中間変数が不要になるケースもある
($one, $two ) = ($two, $one) - スカラー変数のリストに代入する際、右側の個数が足りない時は、undefとなる
- x..y を使うことで、xからyまでの数値リストとなる(x,yを含む整数値のリスト)
($one, $two, $three) = ( 1, 2 );
print "$one $two $three \n"; # 1 2
配列
# 要素を一つずつ初期化する
$student[0]="tanaka";
$student[1]="suzuki";
# 要素をまとめて初期化する
@animals = ("panda", "kirin" );
# whileでアクセスする
$count = 0;
while ( $count < $#student + 1) {
print $student[$count]. "\n";
$count++;
}
# foreachでアクセスする
foreach $animal ( @animals ){
print $animal . "\n";
}
- 配列の要素数は動的に変化する
- スカラー変数を格納している配列をリストに入れると展開される
- @配列名は2通りの意味を持つ(リストコンテキスト,スカラーコンテキスト)
- リストを代入する・リストに代入する・配列同士を代入する・printで@配列名のみでアクセスする
- スカラー変数に代入する・数値と比較する・数式の一部として使う
- $array[3] = 3;のように書いた場合
- $array[0]から$array[2]はundefの状態で配列が作成される
- $#配列名は最後の要素のインデックスを格納する
- $配列名[-x]で末尾から要素を数えてアクセスできる
- $配列名[-1] = 最後の要素
- $配列名[-3] = 最後から3つ目の要素
- 要素の指定
- [0,1,2]
- [0..2]
コマンドライン引数へのアクセス
- 引数は文字列のリストとして認識される
- $ARGV[0]
- (シェルの話ですが)シングルクオートで囲まないと*(アスタリスク)へはアクセスできない
参照情報
参考書籍・Webサイト
スカラーとベクトル
スカラー = 値を一つ持つ量
ベクトル = 値を複数持つ量