3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Perl入門

Last updated at Posted at 2022-10-13

お久しぶりです、三日坊主のXuです。
最近何かとサーバーサイドの処理を書くことが増えたので、bashコマンドよりも自由度が高く、高速高性能で文書処理できる言語がないかと探していた時にPerlに出会いました(今時Perlかよとか言ってたのごめんなさい)。
今までの記事との方向も大きく変わるかと思いますが、今回はPerlの基礎について書きたいと思います。
まだ学習途中なので随時更新します。
また、もし間違いがありましたら指摘していただけると助かります!

Perlについて

全称:Practical Extractional and Report Language
Pathologicial Ecletic Rubbish Listとも言われたりする()

Perlの特徴:
高速で文書処理を行う開発が行える。
インタプリタとコンパイラの両方の特徴を持つ。
「同じ目的を達成するためのルートは一つだけじゃない」という設計理念のもと作られている。

今回扱うバージョン:

  • Strawberry Perl 5.32.1.1

PATH:

  • Windows: [perl_dir]\site\bin, [perl_dir]\bin
  • Linux: whichコマンドで特定しましょう(ファイルを実行する際に755 permissionを付与する必要があります。)

基本的な文法

変数宣言

まずはとりあえずHelloworldを出力してみましょう。

print "Helloworld\n";
print("Helloworld");
Helloworld
Helloworld

このように、インタプリタ言語とコンパイラ言語両方で同じものを書くことができます。

レキシカル変数

いわゆるローカル変数です。
Perlの変数宣言には「my」と「our」と「local」の三つがあります。
それぞれ「レキシカル変数」、「パッケージ変数」、「ローカル変数」と呼ばれています。
Perlで変数を宣言するときは「our」や「local」の使用はできる限り避け、「my」のみでほぼすべての処理に対応できるようになっています。

my $num;

$num = 5;
print($num);

>>> 5

スカラ変数の初期化

my $num = 5;

配列変数の宣言

my @nums = (1, 2, 3);

ハッシュ変数の宣言

my %score = (math => 80, english => 70);

スコープ(block)

Blockともいいます。

{
  my $num = 2;
}
# ここからは「$num」を利用できない。

User Input

$arg = $ARGV[0];
$echo = <STDIN>;

print("Arg result: $arg\n");
print("Echo result: $echo");

$ARGVほかの言語でもよく使われるargs可変長引数です。
以下のようにファイル名の後に値を入力すると受け取ってくれます。
$ perl <program name> test1

実行途中でこちらが何か入力するのを待ってほしいときは<STDIN>を使います。

$ perl [program name] test1

> test2

>>> Arg result: test1
>>> Echo result: test2

Import modules

モジュール名を指定

use CGI;

通常、Perlでは定義されていない変数に対してundefinedエラーを返しませんが、

my $num = 1;

print($nam);

strictモジュールとmyによる変数宣言を一緒に使うと、変数宣言がない場合に変数を使おうとした場合に、コンパイルエラーになります。

use strict;

my $num = 1;

# 変数名が間違っているのでコンパイルエラーになる
print($nam);

>>> Global symbol "$nam" requires explicit package name (did you forget to declare "my $nam"?)

関数のインポート

use File::Basename 'basename', 'dirname';

Importを実行しない場合

use File::Basename ();

同じ結果を得るのに複数方法あるのはワクワクしますね。

use constant result => 100;

print("You got: ", result, "\n");

use feature 'say';
my $result = 100;

say "You got: $result";

条件分岐

If文

C言語などとほぼ変わらないが、else ifelifではなく、elsif

if ([EXP_1]) {
    [code_1];
} elsif ([EXP_2]) {
    [code_2];
} else {
    [code_3];
}

Unless

if notに当たります。

use strict;

my $data = 1;

unless($data < 0){
    $data--;
};

print($data);

>>> 0

真理値

Perlでの真理値は0"""0"falseに該当し、
上記以外がtrueに該当します。

use constant { false => 0 != 0, true => 0 == 0 };

my @ary = (false, true);

foreach my $a(@ary){
    if ( $a ) { 
        print "($a):true\n";
    }
    else { 
        print "($a):false\n";
    }
}

# ここではfalseは""として表示されます。
>>> ():false
>>> (1):true

ループ

For文

JavaScriptをやったことある人は既視感あるんじゃないかと思います。

for (my $count = 0; $count < 5; $count++){
  print("$count \n");
}

While文

お馴染みの条件式がFlaseになるまで続くループです。
ほかの言語と違って抜け出すときはbreakではなくlastです。

while (1) {
  if ([EXP]) {
    last;
  }
}

または

while (1) {
  last if [EXP];
  [code];
}

do-while

While文との違いとして先にdoブロックの内容を実行して、while()内の処理を実行してから止めるかどうかの判断を行います。

my $i = 4;
do {
    print($i);
} 
while ($i--);

print("\n", $i);

# while文であれば0は表示されません。
>>> 43210
# 最後に$i--を一回実行してから判断してます。
>>> -1

do-until

本質的にdo-While文と変わらない感じで、条件式を最後に評価していますが、違いとしてはフラグの処理をループ内に書けるため、比較自由度が高いと感じます。

my $i = 4;

do {
    print($i);
    $i--
} 
until ($i < 0);

print("\n",$i);

>>> 43210
>>> -1

多重ループから脱出する

$finishというフラグを作って置き、$numの値をチェックするループを抜けた際に$finishに値1を付与し、存在確認の式を満たした際に外枠ループを抜けるというロジックになっております。

my $num = 0;

while (1) {
  my $finish;

  while (1) {
    if ($num == 10) {
      $finish = 1;
      last;
    }
    $num++;
  }
  if ($finish) {
    last;
  }
}

redo

redoは演算子はループの最初に戻ことを意味しています。
この際、ループ内での操作のため、条件式は評価されず、以下のプログラムであれば本来$i = 0の時点でループが止まるはずだが、スキップされているため$i = -1の時にやっとループが中止されます。

use strict;

my $i = 5;

while ($i > 0) {
    $i--;

    if($i == 1){
        redo;
    }

    print("$i");
}

print("\n$i");

>>> 4320
>>> 0

next

redoと対照になるのがnextです。
今回はnext;以降の処理をスキップしているため、条件式は評価されます。

use strict;

my $i = 5;

while ($i > 0) {
    $i--;

    if($i == 1){
        next;
    }

    print("$i");
}
print("\n$i");

>>> 4320
>>> 0

continue block

条件式が再評価される直前に実行されるブロックを定義することができます。
continueで繋がっているブロックは一つのブロックとして判断されます。
一つのブロック内で十分なことがほとんどなので可読性が低くなるため、できる限り使わないほうがいいと思います。

use strict;

my $i = 5;
{
    print("roop_1\n");
    {
        print("roop_2\n");
        $i--;
    } continue {
        redo if $i > 0;
        print("$i\n");
    }
}

>>> roop_1
>>> roop_2
>>> roop_2
>>> roop_2
>>> roop_2
>>> roop_2
>>> 0

List

表記

Perlではかっこ()またはqw()でリストを表現しています。
文字列と一緒にprintすることも可能です。

my @numbers = (1, 2, 3);

print(@numbers);
print("a", "b", "c", (1, 2, 3));
print(qw(1, 2, 3));
print((1, 2, 3)[2]);

>>> abc123
>>> abc123
>>> abc123
>>> 3

要素の追加と削除

要素を追加する際は直接インデックスを指定して追加することができます。
削除の場合はdeleteメソッドで削除できます。

my @numbers = (1, 2, 3);
$numbers[3] = 4;

print(@numbers, "\n");

delete($numbers[1]);

print(@numbers);

>>> 1234
>>> 134

また、Pythonなどと同じく後ろから値を取り出すことができます。
スカラ変数($で定義された変数)に代入することでリストのサイズを得ることができます。

my @letters = ("a", "b", "c");
my $var = @letters;

print($letters[-1], "\n");
print($var, "\n");
# 最大インデックス
print($#var, "\n");

>>> c
>>> 3
>>> 2

Forech文で一個づつ取り出す

for文のパートでは言及しなかったが、foreach文を使うことでリスト内の要素を順序取り出すことができます。
foreach my $<var> (@<list>){...}

my @numbers = (1, 2, 3);

foreach my $num (@numbers) {
  print("$num", "\n");
}

>>> 1
>>> 2
>>> 3

Hash

いわゆる辞書型です。keyとvalueによって構成されます。

Key, Valueの入出力

use strict;

my %dict = (
    data1 => "fun",
    data2 => "boring"
);

print("Learning English is so $dict{data1} \n");

> Learning English is so fun 

まとめて出力する際はかなり楽、結果の値はすべてくっつけて出力しています。

my @dict_keys = keys %dict;
my @dict_values = values %dict;
my $dict_size = %dict;

print("Keys:", @dict_keys, "\n");
print("Values:", @dict_values, "\n");
print("Size:$dict_size");

> Keys:data1data2
> Values:funboring
> Size:2

listと同じように、追加と削除、そしてforeach文でkeyとvalueそれぞれ取り出すことができます。

$dict{data3} = "easy";
delete($dict{data2});

foreach my $key (keys(%dict)) {
  print("$dict{$key}\n");
}

>>> fun
>>> easy

サブルーチン

いわゆるユーザー定義関数です。
何度も呼び出して同じ処理を行う場合に使います。
例えば以下のプログラムでは@data = (1,2,3)というリストを作成し、各要素をそれぞれ1足した結果を出力し、@dataリーバスしたものを@rev_dataとして同じ処理を行うものです。
ここではchangeVlue()というサブルーチン(関数)を定義して実行しています。

use strict;

my @data = (1, 2, 3);
&changeValue(@data);

my @rev_data = reverse(@data);
&changeValue(@rev_data);

sub changeValue{
  my @array = @_;

  foreach my $num (@array) {
    $num++;
    print($num);
  }
  print("\n");
}

Perlの特殊変数

コマンドライン引数 @ARGV

前述したとおり、コマンドラインからスクリプトに値を渡すために使います。

デフォルト変数 $_

スカラ変数が指定されるべき場所で、変数を省略した場合に代替で利用される変数です。
下記コードの実行結果はどれも同じ結果が得られます。

use strict;

my @data = (1, 2, 3, 4);

for(@data){
    print($_);
}
print("\n");

for(@data){
    print;
}
print("\n");

print "$_" for @data;

>>>1234

サブルーチンの引数 `@_

サブルーチン内で値を引き継ぐ引数。

環境変数 %ENV

環境変数にアクセスできます。
環境変数名がkeyのhashになってますので$ENV{<var_name>}で値を確認できます

プログラム名 $0

絶対パスからプログラムを起動した場合は絶対パス、カレントディレクトリからのっばいは相対パスを得ることができる。

Debug

例外処理

die関数

エラーメッセージを出力しPerlスクリプトを終了します。

例外を発生させる

die $message;

> Died at excpt.pl line 1.

プログラム名 line 行番号の形式で表示します。

die("Error");

> Error at excpt.pl line 1.

エラーメッセージを合わせて出力
$!はシステムに対する要求を行った時に発生したエラー

die("Error $!");

eval関数

例外をキャッチしてプログラムが終了するのを防ぐことができます。

eval { 例外が発生する処理 };

通常division by zeroで終了するプログラムを実行しても何のエラー表示しません。

use strict;

eval {
    my $a = 1/0;
};

エラー情報$@を出力するには

print $@;

>>> Illegal division by zero at expt.pl line 4.

プログラム実行

Warning制御

  1. スクリプトを走らせる際に-wを入れることで警告を表示させることができます。
    $perl -w <program name>
  2. スクリプト内で先頭に
    #!/usr/bin/perl -w
    を追加する。
  3. Perl5.6及び以降のバージョンでのみuse warningsプラグマで呼び出すことができます。
#!/usr/bin/perl -w

use warnings

どの部分に対してどの警告が有効か設定できるため、より柔軟性が高いと言えます。

Debug build

プログラムを実行せずにDebugだけを行う場合

$perl -c <program name>

上記二つを同時に行いたい場合は

$perl -cw <program name>
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?