Perl入門・基本的な書き方

# はじめに
PHPerのぼくが、Perlを触った思い出に基本的なことを書いていこうと思います。
というのも、毎回Google先生に聞くのもいいのですが無くなる記事も多くあるので
自分でまとめちゃおうという魂胆です(｀･ω･´)ゞ
初心者のぼくでも少しだけ書けるようになったので基礎をかじる程度にはなれるのかなーと。

# 処理を書く前に
まず、Perlで処理をさらさらーっと書く前に次の２行をファイルに書いておきます。

```pl:hello.pl
use strict;
use warnings;
```

基本的にこの２行はマストです。はい。
エラーをキャッチ&リリースしてくれるんですよ。
まあ、僕のようなPerl初心者に向けた優しいガイドのようなものです。

## use strict
これは変数宣言してるかどうかなどを見てくれます。

例えば

```pl:hello.pl
use strict;

$hello = "Hello World!!!";
```

こう書いて処理を実行してあげると下記のようなエラーが吐き出されると思います。
`Global symbol "$hello" requires explicit package name at hello.pl line 4.`
ちゃんと変数宣言してください、と言われるので

```pl:hello.pl
use strict;

my $hello = 'Hello World!!!';
```

このように、`my`を付けてあげてください。
そうすれば、問題なく動作すると思います。


## use warnings
バグの可能性の高いコードがあれば警告してくれます。
例えば

```pl:hello.pl
use warnings;

my $hello;
print $hello;
```

こう書いて処理を実行してあげると下記のような警告が吐き出されると思います。
`Use of uninitialized value $hello in print at hello.pl line 6.`

変数が未定義のものを使ってますよ、と警告をだしてくれます。
なので、変数に何か値を入れてあげれば問題なく動作します。

## var_dump的なもの
変数の内容を見る方法があるようですね。
PHPでいうvar_dumpのようなものです。

```pl:hello.pl
use Data::Dumper;

#配列 ※詳細は後述
my $alphabet = ['a', 'b', 'c'];
#ハッシュ ※詳細は後述
my $fruit    = {'red' => 'アップル', 'yellow' => 'バナナ', 'green' => 'メロン'};

warn Dumper $alphabet;
warn Dumper $fruit;

#実行結果
$VAR1 = [
          'a',
          'b',
          'c'
        ];
$VAR1 = {
          'green' => 'メロン',
          'yellow' => 'バナナ',
          'red' => 'アップル'
        };
```

## シンタックスチェック
プログラムを実行することなくシンタックスチェックをする方法があります。

```bash:
$ perl -cw file_name.pl
```

実行する前にひとまずこれで確認するといいでしょう。

# 変数

Perlの変数宣言には以下のものがあります。
PHPだとそんなに気にしなかったのですが（僕だけかしら）、Perlだとこうするんですね。
他の言語もこんな感じなのかな？

## スカラ変数

スカラ変数には、文字列や数値を入れることができます。

```pl:profile.pl
my $name = 'アラシダ';
my $age = 26;

print "僕の名前は$nameです\n"; # 僕の名前はアラシダです
print "年齢は$age歳です\n"; # 年齢は26歳です
```

変数を展開する方法は他にもあります。

```pl:profile.pl
print "僕の名前は${name}です\n"; # 僕の名前はアラシダです
print "年齢は${age}歳です\n"; # 年齢は26歳です
```

```pl:profile.pl
print "僕の名前は" . $name . "です\n"; # 僕の名前ははアラシダです
print "年齢は" . $age . "歳です\n"; # 年齢は26歳です
```

###スカラ演算子

もちろん、計算することもできます。

| 　構文例  　|　名称　| 説明 |
|:------:|:---------:|:------------:|
| x + y | 加算        | x と y を足した値 |
| x - y  | 減算       | x から y を引いた値 |
| x * y  | 乗算       | x と y をかけた値 |
| x / y  | 除算       | x を ｙ で割った値  |
| x % y  | 剰余       | x を y で割った余り |
| x ** y | 累乗       | x を ｙ 乗した値  |
| x++    | インクリメント | x に １ を足した値   |
| x--    |　　デクリメント 　 | ｘ から １ を引いた値 |


###比較演算子

比較演算子はこちら。
数値と文字列で違いがあるとは知らなかったです。

| 　数値演算子  　|　文字列演算子　| 説明 |
|:------:|:---------:|:------------:|
| x == y | eq        | x と y が等しいなら真 |
| x != y | ne       | x と y が等しくないなら真	 |
| x < y  | lt       | x が y より小さければ真 |
| x > y | gt       | x が yより大きければ真  |
| x <= y | le       | x が y 以下なら真 |
| x >= y | ge       | x が y 以上なら真  |


んー書いていると分からなくなってくるな。。
間違えていたらご指摘をm(_ _)m


## 配列変数

配列変数は、もうそのまんまです。配列をいれることができます。

ここでちょっと勘違いしてしまいそうなのですが、`@fruit[1]`ではなく、`$fruit[1]`になります。
ふむ。ややこしい。

```pl:fruit.pl
# 配列
my @fruit = ('アップル', 'バナナ', 'オレンジ');

# 表示
print "ぼくは$fruit[1]が好きです\n"; # ぼくはバナナが好きです

# 代入
$fruit[1] = 'メロン';

# 表示
print "ぼくは$fruit[1]が好きです\n"; # ぼくはメロンが好きです
```

### 配列操作

簡単な配列操作を見ていきます。

| 関数 | 説明 |
|:------:|:---------:|
| shift | 先頭の要素を取り出す  |
| unshift | 先頭に要素を追加   | 
| pop  | 末尾の要素を取り出す   | 
| push  | 末尾に要素を追加     | 
| sort  | 配列の順序をソートする   |
| reverse | 配列の順序を逆順にする  |

```pl:fruit.pl
my @fruit = ('アップル', 'バナナ', 'オレンジ');

# 先頭の要素を取り出す
my $apple = shift @fruit;

print "これは$appleです\n"; # これはアップルです
print "@fruit\n"; # バナナ オレンジ

#　先頭に要素を追加
unshift(@fruit, 'マスカット');

print "@fruit\n"; # マスカット バナナ オレンジ

#　末尾の要素を取りだす
my $orange = pop(@fruit);

print "$orange\n"; # オレンジ
print "@fruit\n"; # マスカット バナナ

#　末尾に要素を追加
push(@fruit, 'チェリー');

print "@fruit\n"; # マスカット バナナ チェリー

#　配列の順序をソートする
my @alphabet = ('C', 'A', 'D', 'B', 'E');
@alphabet = sort(@alphabet);

print "@alphabet\n"; # A B C D E

#　配列の順序を逆順にする
@fruit = reverse(@fruit);

print "@fruit\n"; # チェリー バナナ マスカット
```

配列の個数を取得することもできます。

```pl:fruit.pl
my @fruit = ('アップル', 'バナナ', 'オレンジ');
my $cnt = @fruit;

print "$cnt\n"; # 3
```

もっと他にもあるんですけど、基本的な部分はこんなところでしょうかね。

## ハッシュ変数
ハッシュというのは、連想配列のことですね。「キー」と「値」がペアとして存在する配列です。
「％」で始まります。

アクセスの仕方は `$変数名{'key'}` です。
 `%` でアクセスするのはないので間違えないようにしましょう。

```pl:fruit.pl
# ハッシュ
my %fruit = ('a' => 'apple', 'b' => 'banana', 'c' => 'cherry');

# 表示
print "$fruit{'a'}\n"; # apple

# 代入
$fruit{'a'} = 'apricot';

# 表示
print "$fruit{'a'}\n"; # apricot
```

###ハッシュ操作

簡単なハッシュ操作を見ていきます。

| 関数 | 説明 |
|:------:|:---------:|
| keys | すべての「キー」を取り出す  |
| values | すべての「値」を取り出す   | 
| each  | ハッシュに含まれている要素を取り出す   | 
| exists  | 指定したキーがハッシュに存在するかどうか     | 
| delete  | 指定されたハッシュ要素を削除   |


```pl:fruit.pl
# ハッシュ
my %fruit = ('a' => 'apple', 'b' => 'banana', 'c' => 'cherry');

# keys
my @fruit_key = keys %fruit;

print "@fruit_key\n"; # 例 a b c

# values
my @fruit_val = values %fruit;

print "@fruit_val\n"; # 例 apple banana cherry

# each
my ($key, $val) = each %fruit;

print "$key : $val\n"; # 例 a : apple

# exists
exists $fruit{'a'}; # true
exists $fruit{'e'}; # false

# delete
delete $fruit{'a'}; 

print %fruit; # 例 b banana c cherry
```

実行結果に「例」と書いているんですが、返却値の順番にはばらつきがあります。
順番に値を取得して何か処理を書こうとすると思わぬハプニングが起こるかもしれませんのでお気をつけを。

どうしても順番に取得したいのであれば、モジュールを用意する必要があります。
しかし、今回は割愛させて頂きますm(_ _)m

`foreach文`でいこうか、でいいかもしれませんね。

each関数に関しては `while`文と使うことが多いかもしれません。 

```pl:fruit.pl
# ハッシュ
my %fruit = ('a' => 'apple', 'b' => 'banana', 'c' => 'cherry');

# each
while (my ($key, $val) = each %fruit) { 
    print "$key : $val\n";
}

# 実行結果 例
a : apple
b : banana
c : cherry
```


## リファレンス
リファレンスとは、値の代わりにアドレスを指し示すスカラ変数です。
んーなんだか難しい。
まあ、値が置いてある住所を見てるんだなーでいいと思います。

ひとまず、書いていきますね。

```pl:ref.pl
# スカラ
my $apple = 'apple';
# 配列
my @fruit_a = ('banana', 'strawberry', 'grape');
# ハッシュ
my %fruit_h = ("m" => "melon", "p" => "peach", "o" => "orange");


my $apple_ref = \$apple;
my $fruit_a_ref = \@fruit_a;
my $fruit_h_ref = \%fruit_h;
```

各変数の前にリファレンス演算子 `\` を付けてあげます。
そうすると、各変数のアドレスを変数に対して入れてくれます。

これとは別に、リファレンスの作成方法があります。

```pl:ref.pl
# スカラ
my $apple_ref = \'アップル';
# 配列
my $fruit_a_ref = ['banana', 'strawberry', 'grape'];
# ハッシュ
my $fruit_h_ref = {"m" => "melon", "p" => "peach", "o" => "orange"};
```

こちらの方が楽ですし、見た目も綺麗ですね。

リファレンスから変数の値を参照するには、参照先の変数の識別子を変数の頭に付けます。
**デリファレンス** といいます。

```pl:ref.pl
print "$$apple_ref\n";
print "@$apple_a_ref\n";

while( ($key, $val) = each %$ref_hash ) {
    print "$key : $val \n";
}

# 実行結果
# スカラ
apple

# 配列
banana strawberry grape

# ハッシュ 例
o : orange
p : peach
m : melon
```

それぞれの要素に対して操作する場合は下記のようになります。

```pl:ref.pl
# 配列
my $fruit_a_ref = ['banana', 'strawberry', 'grape'];
# ハッシュ
my $fruit_h_ref = {"m" => "melon", "p" => "peach", "o" => "orange"};

# アクセス方法1
print "$$fruit_a_ref[0]\n";    # banana
print "$$fruit_h_ref{'m'}\n";  # melon

# アクセス方法2
print "$fruit_a_ref->[0]\n";   # banana
print "$fruit_h_ref->{'m'}\n"; # melon

# 代入
$$fruit_a_ref[0] = 'blueberry';
print "$$fruit_a_ref[0]\n";    # blueberry

$fruit_h_ref->{'m'} = 'musk melon';
print "$fruit_h_ref->{'m'}\n"; # musk melon
```

アクセス方法1と2は同じ意味です。書き方としては、後者の方がすっきりしてますね。
基本的にはアロー演算子の方がいいと思われます。

参照先のデータタイプを調べる関数がありますので一応ここで。

```pl:ref.pl
# スカラ
my $apple_ref = \'アップル';
# 配列
my $fruit_a_ref = ['banana', 'strawberry', 'grape'];
# ハッシュ
my $fruit_h_ref = {"m" => "melon", "p" => "peach", "o" => "orange"};

print ref $apple_ref;   # SCALAR
print ref $fruit_a_ref; # ARRAY
print ref $fruit_h_ref; # HASH
```


# 制御構文

## 条件文

### if文
おなじみのif文です。基本的に意味は他の言語と同じかと思います。
`else if` ではなくて `elsif` というところだけ気をつければいいかなーて感じですかね。

```pl:control.pl
my $fruit = 'apple';

if ($fruit eq 'apple') {
    print "appleです\n"; 
} elsif ($fruit eq "middle") {
    print "appleではないです\n"; 
} else {
    print "もはやフルーツではありません\n"; 
}

# 実行結果
# appleです
```

### unless文
`if文`とは反対の意味を持っており、「〜では無いとき」という意味になります。

```pl:control.pl
my $fruit = 'banana';

unless ($fruit eq 'apple') {
    print "appleではありません\n"; 
}

# 実行結果
# appleではありません
```

### 三項演算子
`if文`を短くしてくれるのが、三項演算子です。
簡単な処理の場合はこちらを使うほうがすっきりするかもしれませんね。

**`[条件式] ? 真の場合 : 偽の場合;`**

```pl:control.pl
my $fruit = 'apple';

print $fruit eq 'apple' ? "アップルです\n" : "アップルではありません\n";

# 実行結果
# アップルです
```


## ループ文
### while文
while文は、条件式が真の間、ブロック内を実行します。

```pl:control.pl
my $cnt = 0;
while ( $cnt < 10 ) {
    print "$cnt\n";
    $cnt++;
}

# 実行結果
0 1 2 3 4 5 6 7 8 9
```

`$cnt`が10以下である場合、ブロック内が実行されているのがわかるかと思います。

### until文
until文はwhile文の反対で、条件式が偽の間、ブロック内を実行します。

```pl:control.pl
my $num = 1;
until ($num > 10) {
    print "$num\n";
    $num++;
}

# 実行結果
1 2 3 4 5 6 7 8 9 10
```

###for文

```pl:control.pl
for (my $i = 0; $i < 10; $i++) {
    print "$i\n";        
}

# 実行結果
0 1 2 3 4 5 6 7 8 9
```

###foreach文

```pl:control.pl
my @fruit = ('banana', 'strawberry', 'grape');

foreach my $name (@fruit) {
    print "$name\n";
}

# 実行結果
banana strawberry grape
```

###ループ制御

| 演算子 | 説明 |
|:------:|:---------:|
| next | ループをスキップする  |
| last | ループを終了する   | 
| redo | ループの先頭に制御を移す   | 


####next
ループをスキップさせるのが、`next`です。
下記の場合 $cnt = 2 のとき処理をスキップさせるため、実行結果に 2 はありません。

```pl:control.pl
my $cnt = 0;

while ($cnt <= 5) {
    $cnt++;
    
    if ($cnt == 2) {
        next;
    }

    print "$cnt¥n";
  
    #next演算子が実行された場合、この位置に進む
}

# 実行結果
1 3 4 5 6
```

####last
ループを終了させるのが、`last`です。
下記の場合 $cnt = 3 のとき処理を終了させるため、実行結果に 3 以降はありません。

```pl:control.pl
my $cnt = 0;

while ($cnt <= 5) {
    $cnt++;

    if ($cnt == 3) {
        last;
    }

    print "$cnt\n";
}
#last演算子が実行された場合、この位置に進む

# 実行結果
1 2
```

#### redo
ループを先頭にスキップさせるのが、`redo`です。
下記の場合 $cnt = 6 のとき処理を先頭にスキップさせるため、実行結果に 7 が出力されます。
`redo`によって`while文`内の条件式を無視して先頭にスキップしているので、実行結果に 7 が出るわけです。
`next`と似ていますが、挙動が別物なので気をつけないといけませんね。


```pl:control.pl
my $cnt = 0;

while ($cnt <= 5) {
    #redo演算子が実行された場合,この位置に進む
    $cnt++;
 
    if ($cnt == 6) {
        redo;
    }

    print "$cnt\n";
}
# 実行結果
1 2 3 4 5 7
```

# サブルーチン
サブルーチンとは関数のことです。
**`sub サブルーチン名 { 処理 }`**といった形で書いていきます。
サブルーチンの呼び出し方法は**`&サブルーチン名()`**です。

```pl:hello.pl
&hello();

sub hello {
    my $name = 'アラシダ';
    my $age = 26;

    print "僕の名前は$nameです\n"; # 僕の名前はアラシダです
    print "年齢は$age歳です\n"; # 年齢は26歳です
}
```

引数の渡し方は下記のようになります。

```pl:hello.pl
&hello('アラシダ', 26);

sub hello {
    my ($name, $age) = @_;

    print "僕の名前は$nameです\n"; # 僕の名前はアラシダです
    print "年齢は$age歳です\n"; # 年齢は26歳です
}
```

**`@_`**の中に引数が入ってきます。
取得した引数をそれぞれ変数へ入れて使用する形になります。

もちろん、**`return`**で値を返却することもできます。


```pl:hello.pl
my $total = &sum(1, 3);
print "$total\n";

sub sum {
    my ($num1, $num2) = @_;

    return $num1 + $num2;
}

# 実行結果
4
```

# ファイル操作

|  | 説明 |
|:------:|:---------:|
| < filename | ファイル読み込み  |
| > filename | ファイル書き込み（新規・上書き）   | 
| >> filename | ファイル書き込み（追加）   | 

もっとあるのですが、ひとまずこれさえ覚えていればいいかな、と思ってます。

```pl:hello.pl
# ファイル新規・書き込み

my $fh;
my $file_name = 'fruit.txt';
my $fruit = 'apple';

open $fh, "> $file_name";

print $fh $fruit;

close $fh;
```

```pl:hello.pl
# ファイル追加書き込み

my $fh;
my $file_name = 'fruit.txt';
my $fruit = 'banana';

open $fh, ">> $file_name";

print $fh $fruit,"\n";

close $fh;
```

```pl:hello.pl
# ファイル読みこみ

my $fh;
my $file_name = 'fruit.txt';

open $fh, "< $file_name";

while (my $line = <$fh>) {
    print $line;
}

close $fh;
```

# 正規表現
正規表現に関しては、PHPとさほど変わらないですね。

簡単に書き方だけ書いていきます。

```pl:fruit.pl
# パターンマッチ
my $fruit = 'apple';

if ($fruit =~ /a/) {
    print "aが含まれています\n";
} else {
    print "aが含まれていません\n";
}

# 実行結果
# aが含まれています
```


## 置換
正規表現を用いた置換を簡単に見ていきます。

**`置換したい文字列 =~ s/正規表現/置換後の文字列/;`**

```pl:fruit.pl
my $word = '私はappleが好きです';

$word =~ s/apple/banana/;

print "$word\n"; # 私はbananaが好きです

# 改行を削除
my $text = "改行を削除します\n";
$text =~ s/\n//;

print $text; # 改行を削除します
```

# 関数
Perlで用意されている関数を少しだけ見ていきます。

| 関数 | 説明 |
|:------:|:---------:|
| chomp | 行末の改行を削除  |
| map | 配列やハッシュを評価して結果を返す  | 
| grep | 条件を満たすものを取得 | 
| split | 文字列を分割する   | 
| join | 文字列を連結する  | 


```pl:test.pl
# chomp
my $text = "行末の改行を削除します\n";
chomp($text);
print "$text\n"; # 行末の改行を削除します

# map
my @num1 = (1, 2, 3);
# $_ に１つ１つの要素が入ってくる
my @num2 = map {$_ * 2} @num1;

print "@num2\n"; # 2 4 6
 
# grep
my @fruit1 = ('apple', 'banana', 'melon');
my @fruit2 = grep {/a/} @fruit1;

print "@fruit2\n"; # apple banana

# split
my $word1 = "アップル,バナナ,メロン";
my @word2 = split(/,/, $word1);

print "@word2\n"; # アップル バナナ メロン

# join
my $word3 = join(',', @word2);

print "$word3\n"; # アップル,バナナ,メロン
```

# 終わりに
後半とても雑になった感じ満載です！
基本的にこの辺りを押さえとけばいいかなーと思ってます。

Perlを触る機会はあまりないかもしれませんが、触ってみると結構便利だなーと思いました。
このフォーマットでデータ欲しい、と思ってPerlで書いて一人で満足した思い出があります。笑

これをきっかけに少しでもPerlへの理解が深まればいいなと思います！！！