-
会場について
- 飲食・喫煙・トイレetc
-
写真撮影について
-
写真撮影NGな方は、お手数ですが申し出てください。
-
写真はPerl普及団体の JPA ( Japan Perl Association )への活動報告に利用します。
-
- 講師・サポーター紹介
-
せっかく今日集まったので、テーブルで自己紹介をしましょう。
-
話題は自由ですが、以下がオススメです。
-
名前(ハンドルネーム)
-
なぜPerlを勉強してみようと思ったか
-
なぜPerl入学式に参加してみようと思ったか
-
- 前回の復習
- 条件分岐( if文)
- 比較演算子( <, >, ==, !=, eq, ne, gt, lt )
- 論理演算子( &&, || )
- 配列
- 配列の操作( join, split, push, pop, shift, unshift, reverse, sort )
$ cd # ホームディレクトリに移動する
$ pwd # 現在のパスを表示する
$ ls -l # ファイル・フォルダの一覧を表示する
$ mkdir perl-entrance # perl-entrance というフォルダを作成する
$ cd perl-entrance # 作成した perl-entrance フォルダに移動する
$ mkdir 2nd # 2nd というフォルダを作成する
$ cd 2nd # 作成した 2nd というフォルダに移動する
「ホームディレクトリ」とは、ユーザごとに用意された作業場所のようなものです (第1回 第2部)
perl-entrance
ディレクトリがすでにある方は、4行目の mkdir perl-entrance
は省略してください。
今日作成するスクリプトは、この 2nd
ディレクトリの中に入れていくと良いでしょう。
#!/usr/bin/env perl
use strict;
use warnings;
-
#!/usr/bin/env perl
- Perlの実行プログラムの場所を指定する
-
use strict
- 厳密な書式を定めたり、未定義の変数を警告する
-
use warnings
- 望ましくない記述を警告する
-
以下、この資料のサンプルコードでは紙面の都合上「おまじない」を省略しますが、皆さんは必ず記述してください。
print "Hello, World!\n";
-
このように書いたものを、
hello.pl
として保存します。 -
print
は、ターミナルに文字を出力します。 -
Hello, World!
はダブルクォーテーション" "
で囲みます。 -
\n
は改行を表します。 -
行の最後に
;
を忘れずに! -
そして「おまじない」の3行も忘れないこと!
$ perl hello.pl
Hello, World!
-
ターミナルを開きます。
-
perl
から1つスペースを空けてhello.pl
と入力してenterキーを押します。-
プログラムに渡される情報、値などを 引数 といいます。
-
この例では
hello.pl
が引数になります。
-
-
プログラムの中に書いた
Hello, World
が表示されます。
-
「変数」は、いわば「データを格納できる箱」です。
-
Perlの変数には、「スカラ変数」、「配列」、「連想配列(ハッシュ)」という3つの種類があります。
-
3種類の変数は、それぞれの変数の型を示す シジル(sigil) という記号で区別されます。
-
スカラ変数($):1つの要素を格納する。
-
配列(@):複数の要素を「順番に」格納する。
-
ハッシュ(%):複数の要素を「名前 => 値」の組み合わせで格納する。
-
-
配列は第2回、ハッシュ(連想配列)は第3回で解説します。
print "Hello World!"; # -- ここがコメント部 --
# print "Hello! Perl Entrance!"; 行頭に # があるため、printは実行されない
-
各プログラム言語にはスクリプトやプログラムをわかりやすくするために、コメントを入れる仕組みがあります。
-
Perlでは、
#
より右にある文字列は全てコメントとして扱われます。 -
コメントは実行されません。
-
この資料の中でも、 コメントを使ってコードに補足を行います。
my $foo; # 変数を宣言する
$foo = 1; # 右辺の 1 を左辺の $foo に入れる
print "$foo\n";
-
変数を初めて使うときは、先頭に
my
をつけます。変数が利用できるようにすることを「変数を宣言する」といいます。 -
スカラ変数の先頭には、
$foo
のように$
をつけます。$
はスカラ(scalar)
のS
、と覚えるとよいでしょう。 -
=
という記号(代入演算子)を使うことで、「右辺の値」を「左辺のスカラー変数$foo
」に入れる(代入する)ことができます。
my $foo; # 変数を宣言する
$foo = 1; # 右辺の 1 を左辺の $foo に入れる
print "$foo\n"; # 1
$foo = "Hello World"; # 宣言済みなので my は不要
# 右辺の "Hello World" が 左辺の $foo に入る
print "$foo\n"; # Hello World
-
宣言した変数を2回目以降に使うときは、
my
は不要です。my
は変数を宣言する最初のみ必要です。 -
値が入っているスカラー変数に別の値を代入すると、中身が上書きされます
my $foo;
my $bar = 1;
$bar = "Hello World";
-
プログラム言語の参考書には以下の単語が変数名として利用されることがあります。
-
foo, bar, baz
-
hoge, piyo, fuga
-
-
これら「意味のない名前」をつけることで、「サンプル用」「例示用」の変数ということを明示するためです。
-
このような単語を使った変数を「メタ構文変数」と呼称します。
-
これらの変数名は現場のコードでは利用しないようにしましょう。
my $foo = 1;
print "$foo\n"; # ダブルクォーテーションで囲うと「1」が表示される
print '$foo\n'; # シングルクォーテーションで囲うと「$foo\n」が表示される
-
print
を使うことで変数を表示することができます。 -
変数を表示する場合は、
" "(ダブルクォーテーション)
の中に変数を書きましょう。-
" "
の中に変数を書くと、その変数の中身が表示されます。 -
' '
の中では、変数の中身ではなく、書いてあるままに表示されます。
-
変数を使い始めると、プログラムの行数が増え、エラーが入り込むことが多くなってきます。
perlでは perl -wc hoge.pl
と wc
オプションを付けることで、スクリプトを実行する前に、Perlの文法に合っているかどうかのチェックが可能です。
$perl -wc foo.pl
foo.pl syntax OK # この表示が出れば、文法上の問題はない
#!/usr/bin/env perl
use strict;
use warnings;
my $hoge = "Hello" # "hello"の後にセミコロンがない
print "$hoge\n";
- よくありがちなエラーとして、行末の「セミコロン
;
を忘れる」というものがあります。 - 先程のシンタックスチェックや、お約束の3行を書いた場合は次のようなエラーがでます。
syntax error at foo.pl line 7, near "print"
Execution of foo.pl aborted due to compilation errors.
- この場合、7行目のprintの周辺でシンタックスエラーが発生しているという意味になります
Perlに限らず、プログラムのエラーメッセージのほとんどは英語で表示されます。
最初は戸惑うかもしれませんが、エラーメッセージ中にある行番号を手がかりに直前・直後の行でおかしいところを探してみましょう。
また、エラーメッセージそのものをGoogleなどで検索したり、翻訳することでエラー解決への手がかりを掴むこともできます。
エラーが出るのは悪いことではありません。直すべき場所を明示してくれるありがたい指針です。
エラーを出さずにプログラムを習得することはできません。
落ち着いて対処していきましょう。
-
Perl入学式とYAPCの情報をスカラ変数に格納し、それらの値を表示するスクリプト
scalar_practice.pl
を作成しよう!seminar_name
この勉強会の名前date
今日の日付venue_name
会場名pre_yapc_pref
前回のYAPCの場所
-
「お約束」の3行を忘れずに!
my $foo = 4;
my $bar = 2;
my $result;
# 足し算 +
$result = $foo + $bar; # 足し算 して $result に代入する
print "$foo + $bar = "; # 式の表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
# 引き算 -
$result = $foo - $bar; # 足し算 して $result に代入する
print "$foo - $bar = "; # 表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
- 算数と同じ + と - が利用できます。
my $foo = 4;
my $bar = 2;
my $result;
# 掛け算 * (アスタリスク)
$result = $foo * $bar; # 掛け算 して $result に代入する
print "$foo * $bar = "; # 表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
# 割り算 / (スラッシュ)
$result = $foo / $bar; # 足し算 して $result に代入する
print "$foo / $bar = "; # 表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
my $foo = 4;
my $bar = 2;
my $result;
# べき乗 **
$result = $foo**$bar; # 4 の 2乗 を $result に代入する
print "$foo ** $bar = "; # 式の表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
# 剰余 %
$result = $foo % $bar; # 4 を 2 で割った余りを $result に代入する
print "$foo % $bar = "; # 表示だけ。改行はしない。
print "$result\n"; # 上の式に続けて $result を表示する
剰余は、初めて聞く言葉かもしれません。利用例を解説します。
print 100 % 7; # 100 / 7 の余りである 2
例えば「今日の100日後の曜日」を求めるとき、100日分カレンダーを辿るのは大変です。
1週間は7日なので、7日後は同じ曜日となります。14日後も同じ曜日となります。21日、28日、35日... 7の倍数日後は同じ曜日になります。
これを利用し、100日 を 7日 で割ってみます。剰余は 2 となります。
明日の曜日と同じであれば剰余は 1、 明後日と同じ曜日であれば 2、 と簡単に計算が可能です。
my $foo = 4;
$foo = $foo * 3; # 右辺の計算結果( 4 * 3 )が、左辺の $foo に代入される
print "$foo\n"; # 12
-
代入演算子
=
は、算数のイコールとは性質が異なります。-
算数 :左辺と右辺が等しいことを示す
-
プログラム:右辺の計算結果を左辺に代入する
-
-
上記の例では右辺の「 $foo * 3 」つまり 12 が
=
の左辺$foo
に代入されます。
代入演算子( =
)を利用して、変数の中身を書き換える処理は多いため、専用の記法が用意されています。
my $fuga = 100;
my $hoge = 50;
$fuga += 1; # $fuga = $fuga + 1;と同じ
print "$fuga\n"; # 101
$fuga -= 1; # $fuga = $fuga - 1;と同じ
print "$fuga\n"; # 100
$fuga *= 2; # $fuga = $fuga * 2;と同じ
print "$fuga\n"; # 200
$fuga /= $hoge; # $fuga = $fuga / $hoge と同じ
print "$fuga\n"; # 4
1 ずつ加算することを「インクリメント」といいます。この処理も多用するので、専用の記法が用意されています。
my $foo = 4;
$foo = $foo + 1;# 代入演算子を利用
print "$foo\n"; # 5
$foo += 1; # 省略記法
print "$foo\n"; # 6
++$foo; # 前置インクリメント
print "$foo\n"; # 7
$foo++; # 後置インクリメント
print "$foo\n"; # 8
前置と後置の違いはこちらを参照
my $foo = 2 + 4 * 3;
print "$foo\n"; # 14
my $bar = ( 2 + 4 ) * 3;
print "$bar\n"; # 18
-
演算の順序は、
( )
を付けることで変更することができます。 -
通常の数学と同じく、Perlも「足し算・引き算」より「掛け算・割り算」の優先順位が高いです。
-
2行目では
( )
を付けることで優先順位を変え、「足し算」を先に計算させています。
my $foo = 'hoge';
my $bar = 123;
print "$foo$bar\n"; # hoge123
print $foo . $bar . "\n"; # hoge123
my $buz = $foo . $bar;
print $buz . "\n"; # hoge123
-
.
(ドット)で文字列や変数を連結することができます。 -
連結した文字列や変数を、別の変数に代入することも可能です。
演算の優先順位と結合方向(演算の向き)はperldocのperlopの項に詳細が記載されています。
ただし、これを覚えるのも、他の人に読んでもらうのも大変な労力です。
( )
で演算の順番を明確に示す、数値演算と文字列の連結は分けて書くなど、わかりやすい記述を心がけましょう。
数値演算と文字列連結を混ぜた場合の「アンチパターン(良くない例)」を示します。
my $now = 2019;
my $start_perl_entrance = 2012;
print "Perl入学式は開講" . $now - $start_perl_entrance . "年です\n"; # エラーメッセージの後に -2012年です
「-2012年です」と、おかしな結果になります。これは演算子の優先順位が .
と -
で同じであり, 左結合のため, 左から演算されるためです.
-
まず 「
Perl入学式は開講
」(文字) と 「2019
」(数字) が文字連結されます。(結果:「今年は開講2019」) -
次に、「
今年は開講2019
」(文字) から 「2012
」(数字)を引き算しようとし、おかしな結果になります。
文字と数値計算を明確に分けてから、 計算してから連結するのが確実です.
my $now = 2019;
my $start_perl_entrance = 2012;
print "Perl入学式は開講" . ($now - $start_perl_entrance ). "年です\n"; # Perl入学式は開講7年です
my $period = $now - $start_perl_entrance;
print "Perl入学式は開講" . $period . "年です\n"; # Perl入学式は開講7年です
-
1番目のprint文のように、
( )
で演算の順序を変更することで、正しい結果になります。 -
2番目のように、計算結果を別の変数に入れてから連結するのも良いでしょう。
以下の問題をPerlの四則演算を使って、変数を使わずに解いて表示してください。
-
1+2+3+4+5+6+7+8+9+10
-
100 ー 200
-
1000円の品物を消費税8%で買った時の税込価格
-
半径5mの円の面積(円周率は3.14とする)
以下の問題をPerlの四則演算を使って解いてください。
my $pizza = 10
を使って解いて表示してください
-
10個のピザを5人で分けた時の、一人当たりの個数
-
10個のピザを3人で分けた時の、余りの数
-
これまでは、あらかじめスクリプトに書かれた文字や数字を表示してきました。
-
スクリプトの実行の都度、中身を変える方法として「入力」を用いる方法があります。
-
プログラムやコンピュータに様々な数値や文字列を与えることを「入力」と言います。
- キーボードからの入力、ファイルからの入力、音声入力、カメラ、画面へのタッチ・・・
-
様々な入力のうち、キーボードから入力されるテキストデータのことを標準入力(Standard Input)といいます。
-
入力の終わりはEnterキー 又は returnキー となります。
my $str = <STDIN>; # 標準入力から文字列を受け取り、変数 $str に代入する
chomp $str; # $strの中の末尾の改行を削除する
print $str; # $strを表示する
-
Perl
では、この「標準入力」をスクリプトの中で<STDIN>
と表現します。 -
1行目では、
<STDIN>
で端末から入力された文字列を受け取り、受け取った文字列を変数$str
に代入しています。- 文字列(Strings)を表す変数として
$str
がよく利用されます。
- 文字列(Strings)を表す変数として
-
2行目では
chomp
で行末の改行を削除しています。<STDIN>
は改行が含まれているため、必須の処理です。
print 'input Season > '; # 入力を促すメッセージ
my $season = <STDIN>; # 標準入力 <STDIN> で入力されたものを $season に入れる
chomp $season; # $season に格納された入力から、末尾の改行を削除する
print "Alice loves $season\n"; # 変数を表示して改行する
-
このコードを実行して、
<STDIN>
がどのような働きをするか見てみましょう。 -
このように、標準入力によってスクリプトの実行結果を変えることが可能です。
Your Name?> Taro
Hello Taro!
Your OS?> macOS
macOS is useful OS!
-
"Your Name?> " と画面に表示して名前の入力を求め、入力された名前の左側に Hello、右側に "!" を付けて表示するスクリプト
hello_stdin.pl
を作成しよう。 -
さらに続けて "Your OS?> " と画面に表示して使用中の OS の入力を求め、入力されたOS名の右側に "is useful OS!" を付けて表示させるようにもしてみましょう。
標準入力<STDIN>
から0以外の整数を2つ読み込み、 それらを四則演算(+
, -
, *
, /
)した結果を上の例のように表示するスクリプト calc.pl
を作成しよう。
最初に1
、次に2
を入れた場合、以下のように表示されるスクリプトです。
1 + 2 = 3
1 - 2 = -1
1 * 2 = 2
1 / 2 = 0.5
スクリプトは上から下へ順番に処理されていきます。
しかし、変数の状態に応じてスクリプトの動きを分岐させることができます。これを 条件分岐 といいます。
条件分岐には様々なパターンがありますが、それらを 真 と 偽 の2つの組み合わせで表現します。
真 または 偽 の判断に用いる式を 条件式 といいます。
条件式、と言っても難しいことではありません。
- 信号が青なら、横断歩道を渡っても良い
- 信号が青でないなら、横断歩道を渡ることはできない
これも立派な条件分岐です。
この場合の条件式は「信号が青であるか、青でないかを判断する」ものです。
条件式の結果は 真 または 偽 となります。Perlでは、次の5つの値が「偽」の値として扱われます。
- 数値「
0
」 - 文字列「
'0'
」 - 文字列「
''
」(シングルクォーテーションの連続、間に何もない。空文字ともいう。) - 空のリスト「
()
」 Perl入学式では扱わない undef
(まだ値を設定していないスカラー変数)Perl入学式では扱わない
これ以外の値は、Perlでは全て「真」として扱われます。例示などで真の値が必要なときは数字の 1 が利用されます。
他のプログラミング言語では、true
や false
という単語に 真 または 偽 の意味を持たせたキーワードとして扱われることがあります。
しかし、Perlは true
や false
などで真偽値を表すことはできません。
また特別な意味もありません。
あくまで、Perlでは先に述べた5つの偽値のみが偽、それ以外はすべて真となります。
Perlのif文はこのような構造です。
if ( 条件式 ) {
条件式の結果が 真 の場合に実行されるコード;
}
else {
条件式の結果が 偽 の場合に実行されるコード;
}
先の青信号の例で例えてみます。
if ( 信号が青だ ) {
信号を渡る
}
else {
信号を渡らない
}
Perlのコードです。
if ( 1 ) { # 条件式の結果が明示的な「真」の値である 1
print "OK\n"; # 条件が「真」なので出力される
}
else{
print "NG\n"; # 実行されない
}
if ( 0 ) { # 条件式の結果が「偽」の値である 0
print "OK\n"; # 実行されない
}
else{
print "NG\n"; # 条件が「偽」なので出力される
}
if文は条件式によって実行結果が変わります。この条件式の中で利用するのが 比較演算子 です。まずは数値の比較演算子から紹介します。
== # 右辺と左辺が等しいならば「真」
!= # 右辺と左辺が等しくないならば「真」
< # 右辺より左辺が小さいならば「真」
> # 右辺より左辺が大きいならば「真」
<= # 右辺が左辺以上ならば「真」
>= # 右辺が左辺以下ならば「真」
数値同士を比較するときは、このような記号を用いた比較演算子を使います。
my $foo = 1;
if ( $foo == 1 ) {
print "OK\n"; # こちらが表示される
}
else {
print "NG\n";
}
条件式は ( )
の中の $foo == 1
です。
==
は 右辺と左辺が数値として等しければ真 であることを意味します。
条件式内で $foo
が 1
と等しい場合に「真」となり、OK
という文字が表示されます。 $foo
が 1
と等しくない場合は、「偽」となり else
に処理が移って NG
という文字が表示されます。
my $foo == 1; # NG
my $bar = 1; # OK
数値の比較に用いる ==
と、代入の =
を間違えています。
この場合、実行すると以下のエラーが出ます。
Useless use of numeric eq (==) in void context
「おまじない」の3行を忘れた場合はエラーが出ずに危険です。
my $foo = 1;
if ($foo = 1) { print $foo } # NG
if ($foo == 1) { print $foo } # OK
条件式に注目してください。
代入の =
と、数値の比較に用いる ==
を間違えています。
この場合、実行すると以下のエラーが出ます。
Found = in conditional, should be ==
「おまじない」の3行を忘れた場合はエラーが出ずに危険です。
文字列を比較する場合は eq
や ne
といった単語を用いた比較演算子を使います。
eq # equal
ne # not equal
gt # greater than
ge # greater equal
lt # less than
le # less equal
「文字列の大小」とは、文字列の長さではありません。
辞書順に並べた時に前にくるものが小さく、後ろにくるものが大きいという意味です。
条件式に注目してください。
my $foo = 'hello';
if ( $foo eq 'hello' ) {
print "OK\n"; # こちらが表示される
}
else {
print "NG\n";
}
文字列を比較しているので、 ==
ではなく eq
を用いています
#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 'perl'; # 好きな文字を入力しておく
簡単な文字当てゲーム question_word.pl
を作成しよう。
-
ターミナルから標準入力で文字列を一つ入力します。
-
その文字列が
$answer
と一致したらOK
と表示します。 -
外れたら
NG
と表示します。
print "eq で評価すると、";
if ( '51.0' eq 51 ) {
print "文字列'51.0' と 数値 51 は等しい\n";
}
else {
print "文字列'51.0' と 数値 51 は等しくない\n"; # こちらが表示される
}
eq
は文字列を比較するときに使う比較演算子です。
このため、条件式の左辺・右辺は文字列として 異なる と判断されます。
print "== で評価すると、";
if ( '51.0' == 51 ) {
print "文字列'51.0' と 数値 51 は等しい\n"; # こちらが表示される
}
else {
print "文字列'51.0' と 数値 51 は等しくない\n";
}
条件式の比較演算子を eq
から ==
に変更すると、先ほどとは逆の結果となります。
==
は数値を比較するときに使う比較演算子です。
このため、条件式の左辺・右辺は数値として 等しい と判断されます。
elsif
を使うことで、分岐条件を増やすことができます。
my $foo = 1;
if ( $foo == 1 ) {
print '$foo is One' . "\n"; # これが表示される
}
elsif ( $foo == 2 ) {
print '$foo is Two' . "\n";
}
elsif ( $foo == 3 ) {
print '$foo is Three' . "\n";
}
else {
print '$foo is not even One, even Two, even Three' . "\n";
}
else if
ではなく、 elsif
です。
##論理演算子
if文
の条件式で複雑な条件を扱いたいときは 論理演算子 を用いて複数の条件を連結します。
&& # かつ
|| # または
-
&&
演算子は「かつ・AND」の意味を持つ。両辺の条件が 真 となるときのみ 真 となる。 -
||
演算子は「または・OR」の意味を持つ。両辺のうち、片方が 真 ならば 真 となる。
条件式に注目してください。
my $foo = 10;
if ( $foo > 0 && $foo % 2 == 0 ) { # $fooが 0 より大きい かつ 2 で割り切れる
print "&& : OK\n"; # こちらが表示される
}
else{
print "&& : NG\n"
}
&&
の左辺にある$foo
が 0 より大きいので、$foo > 0
を満たす。&&
の右辺にある$foo
を 2 で割った剰余は 0 なので、$foo % 2 == 0
も満たす。- 「1. かつ 2. が 真」の条件を満たすので、条件式は 真 となり、
&&: OK
と表示される。
条件式に注目してください。
my $foo = 10;
if ( $foo > 0 || $foo % 2 == 1 ) { # $fooが 0 より大きい または 2 で割り切れない
print "|| : OK\n"; # こちらが表示される
}
else{
print "&& : NG\n"
}
$foo
が 0 より大きいので、$foo > 0
を満たす。- 「1. または 2. が 真」の条件のうち、「1. が 真 」を満たすので、条件式は 真 となり、
||: OK
と表示される。
my $small = 10;
my $medium = 20;
my $large = 30;
if ( $small < $medium < $large ) { # 間違った条件式!
print "小さい順に並んでます\n";
}
$small < $medium < $large
のよう、に3つ以上の値を同時に比較することはできません。
下記のようなエラーとなります。
syntax error at sample.pl line 5, near "$medium <"
my $small = 10;
my $medium = 20;
my $large = 30;
if ( $small < $medium && $medium < $large ) {
print "小さい順に並んでます\n";
}
$small < $medium
かつ $medium < $large
というように、論理演算子を使って比較します。
#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 10; # 好きな値を入力しておく
簡単な数当てゲーム question_num.pl
を作成しよう。
ターミナルから数字を一つ入力し、その数字とスクリプト中の $answer
と比較して以下のように表示してください。
-
$answer
と一致したらOK
-
$answer
より大きければtoo big
-
$answer
より小さければtoo small
-
(余裕があれば)入力した値が
$answer
から -5 〜 +5 の範囲内(例えば、$answer
が10なら 5〜15)の場合、near
と表示する。
今まで学んできた変数はスカラー変数という、1つの値のみを格納する変数でした。
例えば、小学校の4教科の平均点数を出すとき、$kokugo, $sansuu, $shakai, $science と都度スカラー変数を4つ書いて計算するのは大変です。
そこで、「複数の値」や「複数のスカラー変数」をまとめて扱うことのできる 配列、配列変数 を紹介します。
まずは、右辺に注目してください。
my @array = ( 1, "foo", 3 );
( )
の中の 1
, "foo"
, 3
それぞれを 要素 といいます。要素は ,
で区切られています。
右辺の ( 1, "foo", 3 )
の部分を リスト といいます。
このリストはスクリプトに書かれている通りの「要素の集合」でしかなく、スクリプトが加えたり減らしたりすることができません。
そこで、このリストを配列に代入することで、Perlが配列内の要素を操作することが可能になります。
左辺に注目してください。
my @array = ( 1, "foo", 3 );
スカラー変数と同じく、初めてその配列を使うときは my
で宣言します。
同様に =
演算子を使うことで、右辺のリストを左辺の配列に代入することができます。
配列は変数名の前に @
をつけます。
@
は アレイ(array)
、 @rray
、と覚えるとよいでしょう。 (arrayは配列を意味する英単語です)
my @array = ( 1, "foo", 3 );
print "@array" . "\n"; # 1 foo 3
配列はスカラー変数と同じく " "
ダブルクォーテーションで囲むことで変数展開が可能です。
配列の要素を利用する方法です。
my @array = ( 1, "foo", 3 );
print "$array[0] . "\n"; # 1
配列 @array
の最初の要素は $array[0]
となります。
この時、シジルが配列を示す @
からスカラー変数の $
になっていることに注目してください。
これは 取り出す要素の数が1つだけなのでスカラー変数となる ためです。
配列から複数の要素を取り出すときには配列スライスを利用します。この時のシジルは @
になります。Perl入学式では説明しません。
配列から要素を利用する際には、 添字 を使います。
my @array = ( 1, "foo", 3 );
print "$array[0]\n"; # 1
print "$array[1]\n"; # foo
print "$array[2]\n"; # 3
配列の1つ1つの要素にアクセスする場合は $変数名[添字]
を使います。
配列の添字は数字で指定します。
配列の先頭の要素の添字は 0 となり、末尾に向けて 1 ずつ増えます。
配列の添字には、数値が入ったスカラー変数を置くこともできます。
my @array = ( 1, "foo", 3 );
my $i = 1;
print "$array[$i]" . "\n"; # foo
配列の要素に代入することも可能です。
my @array = ( 1, "foo", 3 );
$array[0] = "bar"; # 先頭の要素に文字列 "bar" を代入する
print "@array" . "\n"; # bar foo 3
配列に新たな要素を代入する際は、取り出すときと同様に添字を使って要素を指定します。
配列に、別の配列の中身を追加することもできます。
my @array_one_two = ( 1, 2 );
my @array_numbers = ( @array_one_two, 3 );
print "@array_numbers" . "\n"; # 1 2 3
配列の要素はスカラ変数と同じように扱うことが可能です。
my @array = ( 1, "foo", 3 );
my $sum = $array[0] + $array[2]; # my $sum = 1 + 3
print "$sum\n" # 4
添字を利用して配列の要素同士で足し算をしています。
my @array = ( 1, "foo", 3 );
my $count_array_element = scalar @array; # 要素の数を取得
print "$count_array_element\n"; # 3
my $last_array_index = $#array; # 配列の末尾の要素の添字を取得
print "$last_array_index\n"; # 2
-
scalar
関数の引数に配列を与えると、配列に格納されている 要素の個数 を取得できます。 -
配列
@array
に対して$#array
と書くことで、配列に格納されている 末尾の要素の添字 を取得できます。
連続する数字を配列に格納するときは 範囲演算子 ..
が便利です。
my @array1 = ( 1 .. 5 );
print "@array1" . "\n"; # 1 2 3 4 5
-
1 .. 5
と書くことで、1 から 5 までの連続する値を配列に代入できます。 -
ただし「左側の数値より右側の数値が大きい」必要があります。
my @array2 = ( 5 .. 1 );
print "@array2\n"; # (何も表示されない)
print scalar @array2 . "\n"; # 0
配列の要素を、順番に「すべて」処理する方法として、for文 があります。
my @array = ( 1, "foo", 3 );
for my $element (@array) {
print "$element\n"; # 1 foo 3 がそれぞれ改行されて表示される
}
この場合、変数 $element
に 配列 @array
の先頭から順番に要素が格納されていきます。
最初に $array[0]
, $array[1]
, $array[2]
とスカラー値が順番に代入され、処理(print)が行われます。
for文と範囲演算子を組み合わせることで、決まった回数だけ処理を繰り返すことができます。
- カウントアップ
for my $i ( 1 .. 50 ) {
print "$i\n"; # 1 から 50 まで 1つずつ改行されて表示される
}
- 単なる繰り返し
for my $i ( 1 .. 50 ) {
print "Hello, World\n"; # Hello, World が 50回表示される
}
-
配列
@array
に好きな数値や文字列を設定し、for文で出力してください。 -
<STDIN>
を用いて配列@array2
に好きな数値や文字列を入力し、for文で出力してください。-
2つの入力値を得る場合、配列の要素として
<STDIN>
を直接書くことはできません。my @array = ( <STDIN>, <STDIN> ); # NG
-
1つずつスカラー変数で受け取り、
chomp
をした後で配列に入れましょう。
-
-
for文を使って
1
から100
までを出力してみましょう。 -
次に
1
から100
までのうち、偶数のみを出力するようにプログラムを変えてみましょう。-
ヒント: Perlでは計算の剰余を求める
%
演算子があります。 -
例えば
5 % 3
は 5 を 3 で割った余りですので2
が求まります。
-
1から100までの数字について、以下のようなルールに従って表示を行う fizzbuzz.pl
を作成しましょう。
- その数字が
3
で割り切れるならFizz
と表示する。 - その数字が
5
で割り切れるならBuzz
と表示する。 - その数字が
3
でも5
でも割り切れるならFizzBuzz
と表示する。 - その数字が
3
でも5
でも割り切れないなら その数字 を表示する。
コンピュータサイエンス学科卒業生の過半数にはそれ(fizzbuzz)ができないのだ
どうしてプログラマに・・・プログラムが書けないのか?
関数 とは、ある働きをもつ機能のことです。
いままで変数の中身を表示してきた print
も関数です。
配列に関係する関数を、まずは2つ紹介します。
-
join
- リストや配列の要素を連結してスカラー値にする
-
split
- 文字列やスカラー変数の値を分割して、リストにする
join
はリストや配列の要素を連結して、スカラー値にする関数です。
my @words = ( 'I', 'Love', 'Perl.' ); # 配列を作る
my $poem = join '_', @words; # 第1引数 _ , 第2引数 @words
print $poem . "\n"; # I_Love_Perl.
-
join
が受け取る第1引数 (上の例では _ アンダースコア) は、リストや配列の要素をくっつける糊のような役割を果たします。 -
第2引数には、対象の配列やリストを渡します。
split
は指定したパターンに従ってスカラー値や文字列を分割し、リストにします。
my $poem = 'I_Love_Perl.';
my @words = split /_/, $poem;
print "@words\n"; # ('I', 'Love', 'Perl.')
-
split
が受け取る第1引数 (上の例ではアンダースコア) は、文字列を分割する区切りのような役割を果たします。 -
第2引数には、対象の文字列を渡します。
-
/ /
は正規表現リテラルと呼ばれるものです。この二つのスラッシュ/
の間 にあるもので文字列を分割します。上記の例では、アンダースコア(下線)で文字列を区切っています。
次の処理をする join.pl
を作りましょう。
-
("0120", "123", "XXX")
という配列を作ってください。 -
作成した配列をjoin関数を利用して
-
で連結して表示してください。
次の処理をする split.pl
を作りましょう。
- "There's more than one way to do it." という文字列を作り、split関数で
" "
(半角スペース)ごとに分割して配列@array
に格納し、すべて出力してください。
引き続き、配列の操作を学んでいきます。
配列やリストの用途は主に2つです。
-
名簿など、要素の 単純な集まり として表現したい場合。
-
ランキングなど、要素間の 順序 関係を表現したい場合。
これらの用途においては、要素の順番の並べ替えや、要素の追加、取り出しが必要になります。
まずは追加と取り出しを学んでいきます。
-
要素の追加
- push
- unshift
-
要素の取り出し
- pop
- shift
追加 | 取り出し | |
---|---|---|
末尾 | push | pop |
先頭 | unshift | shift |
push / pop は配列の末尾の値を操作する関数です。
my @array = ( 'Alice', 'Bob' );
push @array, 'Chris'; # 末尾に要素 Chris を追加する
print "@array" . "\n"; # Alice Bob Chris
my $element = pop @array; # 末尾の要素 Chris を取り出す
print "@array" . "\n"; # Alice Bob
print "$element" . "\n"; # Chris
-
配列の 末尾に要素を追加 するときには
push
を利用します。 -
配列の 末尾から要素を取り出す ときには
pop
を利用します。
unshift / shift は配列の先頭の値を操作する関数です。
my @array = ( 'Alice', 'Bob' );
unshift @array, 'Chris'; # 先頭に要素 Chris を追加する
print "@array" . "\n"; # Chris Alice Bob
my $element = shift @array; # 先頭の要素 Chris を取り出す
print "@array" . "\n"; # Alice Bob
print "$element" . "\n"; # Chris
-
配列の 先頭に要素を追加 するときには
unshift
を利用します。 -
配列の 末尾から要素取り出す ときには
shift
を利用します。
次の処理をする array_pop_shift.pl
を作りましょう。
-
('Alice', 'Bob', 'Chris') という配列
@array
を作ってください。 -
配列
@array
から 'Chris' を取り出し、出力してください。 -
配列
@array
から 'Alice' を取り出し、出力してください。
次の処理をする array_push_unshift.pl
を作りましょう。
-
('Alice', 'Bob', 'Chris') という配列
@array
を作ってください。 -
配列
@array
の末尾にDiana
を追加し、 ('Alice', 'Bob', 'Chris', 'Diana') という配列を作ってください。 -
配列
@array
の最初にEve
を追加し、 ('Eve', 'Alice', 'Bob', 'Chris', 'Diana') という配列を作ってください。 -
配列をfor文で出力してみましょう。
reverse はリストを逆順に並べ替えて、そのリストを返す関数です。
my @lang = ( 'perl', 'php', 'ruby', 'python', 'java', 'go');
my @reversed = reverse @lang;
print "@reversed" . "\n"; # go java python ruby php perl
連番を逆順で配列に格納したいときは、範囲演算子と組み合わせると便利です。
my @array = reverse( 1 .. 5 );
print "@array" . "\n"; # 5 4 3 2 1
sort は配列をルール順に並べ替えて、その配列を返します。
sort
のみ、あるいは sort { $a cmp $b } @array
と書くと、「文字列」として昇順に( a
から z
へ)並べ替えます。
my @lang = ( 'perl', 'php', 'ruby', 'python', 'java', 'go' );
my @sorted_lang = sort @lang;
print "@sorted_lang" . "\n"; # go java perl php python ruby
my @num = ( 5, 200, 40, 3, 1 );
my @sorted_num = sort @num;
print "@sorted_num" . "\n"; # 1 200 3 40 5
sort { $a <=> $b } @array
と書くと、「数値」として昇順(小さい順)に並べ替えます。
my @num = ( 5, 200, 40, 3, 1 );
my @sorted = sort { $a <=> $b } @num;
print "@sorted" . "\n"; # 1 3 5 40 200
変数 $a
と $b
はsortで使うために予約されているので、 sort以外で使わないようにしましょう。
「数値」として降順(大きい順)にソートする場合、以下の2つの書き方ができます。
- sortブロック内の $a と $b を入れ替える方法
my @num = ( 5, 200, 40, 3, 1 );
my @sorted1 = sort { $b <=> $a } @num;
print "@sorted1" . "\n"; # 200, 40, 5, 3, 1
- sortした結果をreverseで逆順にする方法
my @num = ( 5, 200, 40, 3, 1 );
my @sorted2 = reverse sort { $a <=> $b } @num;
print "@sorted2" . "\n"; # 200, 40, 5, 3, 1
- practice.md
- 今回の内容を復習することができる問題集です。
- ご不明な点があれば、気軽にスタッフまでお尋ねください。
-
- 各会場の講師が書いた、練習問題の解答例はこちらで公開しています。
- ※講義終了後に随時追加していきます。
-
- 昨年分の解答例はこちらで公開しています。
-
- 一昨年分の解答例はこちらで公開しています。
-
長い時間、Perl入学式第2回お疲れ様でした!
-
是非Perl入学式のslackに参加して、サポーターや参加者の皆さんと交流しましょう。
-
不明点もslackで是非質問してください。
-
第3回以降の参加もお待ちしております!
-
ハッシュ
-
正規表現
-
リファレンスがないとできないこと
my @array = ( 1, "foo", 3 );
my $i = 0;
while ( $i < scalar(@array) ) {
print "$array[$i]\n";
$i++;
}
-
while
ループを使うことで、for
ループと同じような繰り返し処理が可能です。 -
while
の()の中には、繰り返しを行うための条件式を書きます。 -
条件式が「真」である限り、whileループは動き続けます。
forループでもwhileループでも同じ処理は書けますが、それぞれ適している・好まれるケースがあります。
-
forループは配列全てに対して処理を行う時など、繰り返す回数が決まっている場合に好まれる書き方です。
-
whileループは繰り返す回数は決まっていないが、特定の条件が真の間、ずっと処理を繰り返したいときに好まれる書き方です。
-
whileループの条件式を間違えると、応答がなくなる「無限ループ」という状態に陥ります。その時は Ctrl(Control)キーを押しながらCを押すことで強制的に止めることが可能です。
my @array = qw( Alice Bob Chris ); # ('Alice', 'Bob', 'Chris')
リストの先頭に qw
とつけることで、リスト内の要素にクオォーテーションが不要になります。
上記の例では空白文字 (スペース, タブ, 改行など) が区切りとなり、残ったものがリストの要素になって配列 @array
に格納されています。
改行区切りを利用すれば、このような書き方も可能です。
my @arary = qw(
Alice
Bob
);
qw! Alice Bob !
qw# Alice Bob #
qw/ Alice Bob /
デリミタ (区切り文字) には任意の記号文字を使えます。これらは下記の表記と等しいものです。
qw( Alice Bob )
my @array = qw(1 .. 50);
print @array; # 1..50
qwショートカットと範囲演算子を同時に利用することはできません。