Perl Cheet Sheet v5

# Perl v5 自分用メモ
とかくperlは書き方が自由すぎる。いちいち調べていたら、小さなプログラムでも書くのに時間がかかる。また、はまるポイントも色々ある。
そのため、ここに文法と注意点をまとめます。自分のメイン言語がJavaのため、たまに比較します。
言語としては「**P**erl」、実行プログラムとしては「**p**erl」として、この記事を書いたつもりです。また、「変数」とだけ書いてある場合は、大抵スカラー変数のことです。
#### 実行環境のperl
v5.18.2

## TL;DR

- メモです
- 今更ですがv5のPerlです
- Nothing new here

## 言語思想
実用性と多様性

## コメント
- 単一行コメント(#)  
\# This is a comment   
さすがUNIX上での作業が発端となった言語、シェルスクリプトと同じですね。   
- 複数行コメント(=pod / =cut)  
=pod  
multi-line comments  
=cut

## print
- カッコで囲っても囲わなくても良い。

```perl:print
print "hello\n";
print ("hello\n");
```
- printの直後にカッコがあると閉じタグでその行の解釈が終わる。  

```perl:print 
print (2 * 3) /2 ; # 結果は6
print (2 * 3 / 2); # 結果は3
print  2 * 3 / 2 ; # 結果は3
```


## 累乗計算
\*\* 演算子が使える。

```perl:** 
print 2 ** 3 ; # 8
```

JavaならMath.pow(2.0, 3.0)ですね。
正の平方根を返すsqrt()関数はPerlにもある。というか、Perlの方がJavaより古い。(Wikipedia調べ、Perl=1987/Java=1995)

## ワンライナー
-eをつけて実行

```perl:one-liner
perl -e 'print 2 ** 3;' # 8
```

## 桁が大きな数の、科学技術表記が可能
エクセルみたいに、「1e+200」という表記ができる
「1e+200」は、10の200乗です。

## インクリメントは前置・後置ともに実行可能


## 複数変数への同時代入の仕方
```perl:Multi-Variable
perl -e '$a = $b = $c = 5; print "$a $b $c\n";' # 結果：5 5 5
```
Javaだとこう書けない。int a = 5, b = 5 , c = 5; となる。

## おまじない

```perl:use   
use strict;
use warnings;
```
- strict  
変数などを使う前に宣言を必要とする
- warnings  
初期化していない変数にアクセスした場合などに警告を出す  
チェックする内容としては、perl -wオプションと変わらないみたですが、use warningsの場合は、記述したファイルに適用範囲が限定されるみたです。また、use strict "vars"; やuse strict;
 no strict "vars";　のように適用する対象を分けることもできる。
- プラグマ(pragma)  
strictやwarningsなどはPerlプラグマと呼ばれる、機能拡張モジュールです。小文字でプラグマ名を書く慣習らしいです。

参照：[PerlPlus 厳密な構文チェック](http://www.perlplus.jp/perl/ini/index4.html)
　　　[perldoc.jp 5.12.3 strict](http://perldoc.jp/docs/perl/5.12.3/strict.pod)
　　　[Perl/ライブラリ・モジュールとオブジェクト指向](https://ja.wikibooks.org/wiki/Perl/ライブラリ・モジュールとオブジェクト指向)

## 文字列結合
. (ピリオド、ドット)で結合する。複合代入演算子としても使える。(.=)
Javaは+, Excel関数だと&ですか。
Perlは動的に変数の型を決める(というか数値も文字列も許容する)ので、. と + で色々使い分けることが可能です。

```perl:concatnate
$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](http://amzn.to/2fn1vnq))

## 判定式・条件式
Perlには真偽値という型はないらしく、次のコードのifブロックは実行されます。  

```perl:false
if ( false ) { 
  print "実行されます\n"; 
}
```
#### Perlで偽と判定される文字列や数値 

1. undef
1. ""  (空文字)
1. "0" (文字列のゼロ)
1. 0   (数値のゼロ)

参照：[PerlPlus 論理値(ブール値)](http://www.perlplus.jp/perl/num/index5.html)


### 文字列の一致はeq , 数値の一致は==
:rotating_light:シェルスクリプトと混ぜるな危険!
シェルスクリプトだと、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<br>  〜<br>ElseIf 条件式2 Then<br>  〜<br>Else<br> ~<br> **End If**|
|Python|if 条件式1:<br>タブ~<br>**elif** 条件式2:<br>タブ~<br>else:<br>タブ~<br>|

※ Mac OS用のExcel持っていないのでおうちで試せてませんが、Excel VBAは改行が必要な気がします。 
※ 左詰めした表の中にスペースが入らないので、苦肉の「タブ」

### unless
英語の意味のとおり、「〜しない・〜でない限り」実行するブロック。つまり、条件式が偽の時に実行される。elseブロックを追加できて、unlessのelseブロックは条件式が真の時に実行される。
参照：[PerlPlus unless文](http://www.perlplus.jp/perl/if/index6.html)

```perl:unless 
unless ( 2 == 1 ) { print "unless"; } # こちらが実行されます
else { print "unless else" }          

if ( 2 == 1 ) { print "if"; }         
else { print "if else"; }             # こちらが実行されます
```

多分、他言語では実装されていないことが多いので、チームでの読みやすさを考慮するとunlessは書かないほうがいのかなと感じました。ifのelseブロックを使うか、ifの条件式を反転(!)させることで代用できるので、unlessである必要性はない。まぁ、好み・宗教問題ですね。

```perl:reversedIf
if ( ! (2 == 1) ) { print "if"; }       # こちらが実行されます  
else { print "if else"; }          
```
※ !==より優先順位が高いので、は(2==1)というように()でくくらないと判定式を反転できない
※ (追記)notは==より優先順位が低いので、()で囲う必要がない

Pythonだとif notでunlessと同じことができるみたいです。
（参照：[Chat-blog 【python】unlessがないのでnotを使う](http://chat-rate.com/it/255)）

## 論理演算子
& <=> &&, | <=> || の描きわけで、短絡評価するかどうかを書き分けることが可能。
&&, || は短絡評価(ショートカット)するので、true/falseを判定した時点で、もし右側に判定式が続いてても評価しない。Javaと同じ。

### 論理演算子の種類
上にあるほうが評価の優先順位が高い。

|結合方向|演算子　|
|:--|:--|
|左結合|項(丸括弧で囲った部分)  リスト演算子 (左方向に対して)|
|右結合|!|
|非結合|**==** != <=> eq ne cmp|
|左結合|&|
|左結合|&#x7C;　^|
|左結合|&&|
|左結合|**&#x7C;&#x7C;**|
|右結合|**= += -= \*= などの代入演算子**|
|右結合|not|
|左結合|and|
|左結合|or xor|


### デフォルト値を設定する
結論からすると、defined関数を使って、undefかどうかでデフォルト値を設定しましょう。

```perl:default
$result = defined $results{$name} ? $results{$name} : "not taken" ;
```
参照：[blog 20100901 / Perl 「 論理演算子 」論理 OR を利用したデフォルト値の設定とその問題点 (0x8c)](http://pointoht.ti-da.net/e6084669.html)

公式ドキュメント日本語訳に下記のような例が載っていました。
> \$a = \$b || \$c;
引用：[論理和と排他論理和](http://perldoc.jp/docs/perl/5.6.1/perlop.pod#Logical32or32and32Exclusive32Or)

=(代入演算子)より||の方が評価優先順位が高いので、\$bまたは\$cの結果を\$aに代入できます。&#x7C;&#x7C;と=でもデフォルト値を設定することがように見えますが、\$bが下記の値の場合、予期せず\$cが評価される場合があるみたいです。
- ""  (空文字)
- "0" (文字列のゼロ)
- 0   (数値のゼロ)

### or die
die関数はプログラムを終了させる関数で、orは上記にもある論理演算子です。
ファイルのオープン時に組み合わせます。
[こちらの記事](http://vivibit.net/perl-or-die/)になぜ「||」ではいけないかがわかりやすく説明されています。

## while
```perl:while
while ( 条件式 ) { 処理 }
```
- last;でループを抜けることができる


## foreach
```perl:foreach
foreach $val ( @array ) { $valを使った処理; }
```
Javaとは違うのだよ、Javaとは。
for (データ型 変数名: コレクション) { 変数を使った処理; }


## コアダンプ
coreという名前のファイルを出力しプログラムが異常終了すること。

## メソッド(関数)一覧
|メソッド名|動作|使い方|
|:--|:--|:--|
|print|数値や文字列を出力する|print "hogehoge";|
|last|ループブロックの終了|last;|
|defined|引数がundefの場合、偽を返す|\$result = defined \$results{\$name} ? \$results{\$name} : "not taken" ;|
|die|プログラムを終了させる|リストを引数に取る<br>改行でdie関数が終わらない場合は、エラー位置を示すエラーメッセジが挿入される|
|eval|引数をperlで一度処理する<br>{}で囲うと一度変換する<br>※実行と変換は違う|eval 1+3; # 4<br>\$temp = "1+2"; <br>eval \$temp; # 3<br>eval { \$temp }; # 1+2



## リスト
- リスト=()で囲んだ複数の値を持つブロック ※ カンマ区切り
- リストを用いることで中間変数が不要になるケースもある  
(\$one, \$two ) = (\$two, \$one)
- スカラー変数のリストに代入する際、右側の個数が足りない時は、undefとなる  
- x..y を使うことで、xからyまでの数値リストとなる(x,yを含む整数値のリスト)
 
```perl:list
($one, $two, $three) = ( 1, 2 );
print "$one $two $three \n"; # 1 2 
```

## 配列

```perl:array
# 要素を一つずつ初期化する
$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";
}
```

- 配列の要素数は動的に変化する
- スカラー変数を格納している配列をリストに入れると展開される
- @配列名は２通りの意味を持つ(リストコンテキスト,スカラーコンテキスト)
    - リストを代入する・リストに代入する・配列同士を代入する・printで@配列名のみでアクセスする
    - スカラー変数に代入する・数値と比較する・数式の一部として使う
- $array[3] = 3;のように書いた場合
    - \$array[0]から\$array[2]はundefの状態で配列が作成される
- $#配列名は最後の要素のインデックスを格納する
- $配列名[-x]で末尾から要素を数えてアクセスできる　　  
    - \$配列名[-1] = 最後の要素  　　
    - \$配列名[-3] = 最後から3つ目の要素
- 要素の指定
    - [0,1,2]
    - [0..2]

## コマンドライン引数へのアクセス
- 引数は文字列のリストとして認識される
- $ARGV[0]
- (シェルの話ですが)シングルクオートで囲まないと*(アスタリスク)へはアクセスできない

## 参照情報
### 参考書籍・Webサイト
[perldoc.jp](http://perldoc.jp/)
[すぐわかるPerl 初版第7刷](http://amzn.to/2fn1vnq)

### スカラーとベクトル
スカラー = 値を一つ持つ量
ベクトル = 値を複数持つ量