- 会場について
- 飲食・喫煙・トイレetc
- 写真撮影について
- 写真撮影NGな方はお手数ですが申し出てください
- 講師・サポーター紹介
- せっかく今日集まったので, テーブルで自己紹介をしましょう
- 話題は自由ですが, 名前(ハンドルネーム)や「なぜPerlを勉強してみようと思ったか(なぜPerl入学式に参加してみようと思ったか)」などがあると, 盛り上がると思います!
- 前回の復習
- おまじない
- 変数
- 標準入力
- 四則演算
- 基本的な演算子
- if, else文
- 論理演算子
- for文, 配列
$ cd
$ pwd
$ ls -l
$ mkdir perl-entrance
$ cd perl-entrance
$ mkdir 2nd
$ cd 2nd
- ホームディレクトリに
perl-entrance
というディレクトリを作り、さらにその中に2nd
というディレクトリを作りましょう perl-entrance
ディレクトリがすでにある方は、mkdir perl-entrance
は省略してください
print "Hello, World!\n";
- このように書いたものを,
hello.pl
として保存します print
は, 端末に文字を出力します\n
は改行を表します- 最後に
;
を忘れずに!
$ perl hello.pl
Hello, World!
perl
の引数に実行するスクリプトファイル名を与えると, そのスクリプトを実行します
#!/usr/bin/env perl
use strict;
use warnings;
- おまじないとして, 冒頭の3行を書くようにしよう
use strict
-> 厳密な書式を定めたり, 未定義の変数を警告するといった効果がありますuse warnings
-> 望ましくない記述を警告してくれる効果があります- 以下, この資料のサンプルコードではこれを「お約束」として省略します
- 書かれているものとして扱ってください
Hello, Perl Entrance!
という文字列を出力するhello_perl.pl
を書いて下さい- わからない所があれば, 近くのサポーターに聞いて下さい!
- 「変数」は, いわば「データを格納できる箱」です
- Perlの変数には, 「スカラ変数」, 「配列」, 「連想配列(ハッシュ)」という3つの種類があります
- 「スカラ変数」は, 「1つの要素しか入らない箱」と思って下さい
- 「配列」と「連想配列(ハッシュ)」は, 「複数の要素を格納出来る箱」と思って下さい
- まずは, 1つの要素を格納できる「スカラ変数」について見て行きましょう
my $foo; # スカラ変数 $foo を宣言
$foo = 1; # $foo に整数 1 を代入
my $bar = 3.14; # $bar を宣言し実数 3.14 を代入
$bar = "baz"; # $bar に文字列 baz を代入
- スカラ変数の先頭には,
$foo
のように$
をつけます$
はスカラ(scalar)
のS
, と覚えるとよいでしょう
=
という記号(代入演算子)を使うことで, 左辺のスカラー変数に右辺の値を入れる(代入する)ことができます- 変数を宣言するとき(初めて使うとき)は, 先頭に
my
をつけます Perl
では, C言語やJavaのようにint
やchar
といった「型」がないので, 数値や文字列などを自由に代入することができます
my $foo;
my $bar = 3.14;
$bar = "baz";
- ところで, ここで出てきた変数名
foo, bar, baz
は, 意味のない「仮の名前」(メタ構文変数)です. このように, プログラミングで変数や関数に名前を付ける際, どのような名前でも良い場合には foo, bar, baz がよく使われます - 日本では hoge, piyo, fuga なども使われますが, 特別の理由がなければ foo, bar, baz で良いでしょう
my $foo = 1;
print "$foo\n"; # 「1」が出力される
print '$foo\n'; # 「$foo\n」が出力される
print
を使うことで変数を出力することができます- 変数を出力する場合は,
""(ダブルクォテーション)
の中に変数を書きましょう""
の中に変数を書くと, その変数の中身が展開されて表示されます''
の中では, 展開はされず, 全てがそのまま出力されます- 変数だけでなく,
\n
などもそのまま出力されます!
- 変数だけでなく,
\n
は改行を意味します
my $foo = 1;
print "$foo\n"; # 「1」が出力される
print '$foo\n'; # 「$foo\n」が出力される
- Perlでは,
#
より後ろの文字列は全てコメントとして扱われます- コメントは, 実行されません
- この資料の中で, コメントを使ってコードに補足を行うことがあります
- Perl入学式とYAPCの情報をスカラ変数に格納し、それらの値を出力するスクリプト
scalar_practice.pl
を作成しよう - 例えば,「この勉強会の名前」,「今日の日付」,「会場名」,「次回のYAPCの場所」などを、
seminar_name
,date
,venue_name
,next_yapc_pref
といったスカラ変数に格納しましょう - 「お約束」の3行を忘れずに!
- 標準入力(Standard Input)とは、プログラムに入ってくるデータです
- 通常, キーボードから入力されるテキストデータのことを指します
Perl
では, この「標準入力」をプログラムの中で<STDIN>
と表現します
my $str = <STDIN>;
chomp $str;
print $str;
- 端末からPerlに対して, 標準入力を使って文字列を入力することができます
- 1行目では,
<STDIN>
で端末から入力された文字列を受け取り, 受け取った文字列を変数str
に代入しています - 2行目では,
chomp
で行末の改行を削除しています<STDIN>
で端末から受け取ったデータには改行が含まれているためです
- 1行目では,
print 'input > ';
my $str = <STDIN>;
chomp $str;
print "$str\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!" を付けて表示させるようにもしてみましょう
my $foo = 4;
my $bar = 2;
my $result;
$result = $foo + $bar; # 4 + 2 = 6
$result = $foo - $bar; # 4 - 2 = 2
$result = $foo * $bar; # 4 * 2 = 8
$result = $foo / $bar; # 4 / 2 = 2
$result = $foo % $bar; # 4 % 2 = 0
$result = $foo ** $bar; # 4の2乗は 16
Perl
はC言語と異なり, べき乗の計算を簡単に行うことができます
my $foo = 4;
$foo = $foo * 3; # 4 * 3 = 12
- 代入演算子
=
は, 算数のイコールとは性質が異なります - 上記の例では右辺の「4 * 3 = 12」が
=
の左辺へ代入され, 左辺の$foo
が「12」になります
my $foo = 4;
my $bar = 2;
$foo = $foo + 1;
$foo += 1;
++$foo; # または $foo++;
# すべて「4 + 1 = 5」
$bar = $bar - 1;
$bar -= 1;
--$bar; # または $bar--;
# すべて「2 - 1 = 1」
- 「1」ずつ加減したい場合は上記のように記述できます
- 「1」ずつ加算することを「インクリメント」, 減算することを「デクリメント」といいます
my $fuga = 100;
my $hoge = 50;
$fuga += 1; # $fuga = $fuga + 1;と同じ
$fuga -= 1; # $fuga = $fuga - 1;と同じ
$fuga *= 2; # $fuga = $fuga * 2;と同じ
$fuga /= $hoge; # $fuga = $fuga / $hoge;と同じ
- 先ほどのスライドの
+=
や-=
といった省略した書き方は、*=
/=
にも利用できます
my $foo = 'hoge';
my $bar = 123;
print $foo . $bar . "\n"; #=> hoge123
print $foo, $bar, "\n"; #=> hoge123
print "$foo$bar\n"; #=> hoge123
.
(ドット)で, 文字列や変数を連結することができます,
(カンマ)でも、スカラー変数や文字列、数値をつなげた場合は、.
と同じ結果になります- カンマの場合は、文字列を連結したわけではなく、複数の引数(コマンドの対象)を渡した結果、同じ表示になっています
- カンマの場合は、
print
文の右側でのみ連結が行われます
"
(ダブルクォテーション)で囲まれた変数は展開されて表示されるので、最後のprint文も同じ結果になります
my $foo = 2 + 4 * 3; #=> 14
my $bar = (2 + 4) * 3; #=> 18
- 演算の順序は,
()
を付けることで変更することができます- 通常の数学と同じく, Perlも足し算・引き算より掛け算・割り算の優先順位が高いです
- しかし, 2行目では
()
を付けることで足し算を先に計算させています
- 演算の優先順位と結合方向(演算の向き)はperldocのperlopの項に詳細が記載されています
my $now = 2017;
my $last_showa = 1988;
print "今年は平成" . $now - $last_showa . "年です\n";
#=> -1988年です
print "今年は平成" . ( $now - $last_showa ) . "年です\n";
#=> 今年は平成29年です
my $heisei = $now - $last_showa;
print "今年は平成$heisei年です\n";
#=> 今年は平成29年です
- 最初のprint文では、
-1988年です
という予期せぬ結果になります -.
と-
は同じ優先順位で左結合のため、左から演算されます - 始めに、今年は平成
と2017
を文字連結します- 次に、
今年は平成2017
から1988
を引き算しようとしているため、正しい計算ができません
- 次に、
- 2番目のprint文のように、
()
で演算の順序を変更することで、正しい結果になりました - 3番目のように、計算結果を別の変数に入れるのも良いでしょう
1 + 2 = 3
1 - 2 = -1
1 * 2 = 2
1 / 2 = 0.5
- 標準入力
<STDIN>
から0以外の整数を2つ読み込み, それらを四則演算(+
,-
,*
,/
)した結果を上の例のように出力するスクリプトcalc.pl
を作成しよう
my $foo = 1;
if ( $foo == 1 ) {
print "OK\n"; # 条件が「真」の場合
} else {
print "NG\n"; # 条件が「偽」の場合
}
==
は"右辺と左辺が数値として等しければ真"であることを意味します- 真 = 条件が正しい / 偽 = 条件が正しくない
- ここでは
$foo
が1
と等しい場合に真となり,OK
という文字が表示されます $foo
が1
でなければ, 偽となるためelse
に処理が移りNG
という文字が表示されます
my $foo == 1; # まちがい
my $bar = 1; # せいかい
- 代入の
=
と, 数値の比較の==
をよく間違えます- この場合, 実行すると
Use of uninitialized value $foo in numeric eq (==)
のようなエラーになります
- この場合, 実行すると
my $foo = 1;
if ($foo = 2) { ... } # まちがい
if ($foo == 2) { ... } # せいかい
- 数値の比較の
==
と, 代入の=
をよく間違えます- この場合, 実行すると
Found = in conditional, should be ==
のような警告が出ます
- この場合, 実行すると
my $foo = 1;
if ( $foo == 1 ) {
print "OK\n"; # 条件が「真」なので出力される
}
else
の部分は省略することもできます- この状況で条件が「偽」の場合(
$foo
が1
ではない場合), 何の処理も行われません
- この状況で条件が「偽」の場合(
== # 右辺と左辺が等しいならば真
!= # 右辺と左辺が等しくないならば真
< # 右辺より左辺が小さいならば真
> # 右辺より左辺が大きいならば真
<= # 右辺が左辺以上ならば真
>= # 右辺が左辺以下ならば真
- 数字同士を比較するときは, このような比較演算子を使います
eq == equal
ne != not equal
gt > greater than
ge >= greater equal
lt < less than
le <= less equal
- 数値を比較する場合は
==
や!=
を使いますが, 文字列を比較する場合はeq
やne
といった演算子を使います- もっとも,
eq
,ne
以外はあまり使いません - 「文字列の大小」とは, 辞書順に並べた時に前にくるものが小さく, 後ろにくるものが大きいという意味です
- もっとも,
my $foo = 'hello';
if ( $foo eq 'hello' ) {
print "OK\n";
} else {
print "NG\n";
}
- 今回は文字列を比較しているので,
==
ではなくeq
を用いています
if ('42strings' == 42) {
print "OK\n";
}
use warnings
が有効であれば, 文字列を数値用の比較演算子で比較しようとすると, 次のような警告を出力しますArgument "42strings" isn't numeric in numeric eq (==)
- このような場合, Perlは文字列を無理やり数値として解釈して処理を継続します
- この場合, '42strings'には先頭に
42
という数値が含まれているので, Perlは==
の演算子の左辺は42
として処理を実行します - そのため, この比較は真となり, 「OK」という文字列が出力されます
- この場合, '42strings'には先頭に
- 一般の文字列を
==
で比較することはバグの元ですので, こういう比較をしないように気をつけましょう
if ('42' eq 42) {
print "OK\n";
}
- 逆に, 文字列の比較演算子で数値を比較しようとした場合, 警告は出力されません
- Perlは自動的に数値を文字列として解釈して,
eq
演算子の右辺は'42'
として扱われます - そのため, この比較は「真」となり, 「OK」という文字列が出力されます
- Perlは自動的に数値を文字列として解釈して,
- Perlには,
true
やfalse
などで真偽値を表すことはできません- 他のプログラミング言語では、
true
やfalse
という単語は特別な意味を持つキーワードとして扱われることが多いです true
は条件が真であることを意味するキーワード、false
は条件が偽であることを意味するキーワードですが、- Perlでは、
true
やfalse
にこのような特別な意味はありません
- 他のプログラミング言語では、
- そのかわりPerlでは, 次の5つの値が「偽」の値(偽値)として扱われます
- 数値「
0
」 - 文字列「
'0'
」と「''
」 - 空のリスト「
()
」 undef
- 数値「
- そしてこれ以外の値は, Perlでは全て「真」として扱われます
- 明示的な真値が必要な場合、数値の
1
を使う場合が多いです
my $foo = 1;
if ( $foo == 1 ) {
...
} elsif ( $foo == 2 ) {
...
} elsif ( $foo == 3 ) {
...
} else {
...
}
elsif
を使うことで, 分岐条件をさらに増やすことができます- PerlにはC言語の
switch
にあたるものはないので,if
,elsif
,else
で代用しましょう
- PerlにはC言語の
#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 'perl'; # 好きな文字を入力しておく
- 簡単な文字当てゲーム
question_word.pl
を作成しよう - 端末から, 標準入力で文字列を一つ入力し, その文字列が
$answer
と一致したらOK
, 外れたらNG
と表示します
&& -> かつ
|| -> または
if文
で複雑な条件を扱いたいときは,関係演算子
を用いて複数の条件を連結しましょう&&
演算子は「かつ」なので, 両方の条件が真となるときのみ真となります||
演算子は「または」なので, 条件のどちらか1つでも真となるならば真となります
my $foo = 64;
if ( $foo > 0 && $foo % 2 == 0 ) {
print "&&: OK\n";
}
if ( $foo > 0 || $foo % 2 == 1 ) {
print "||: OK\n";
}
- 2行目は, 「64は0より大きい(真)」かつ「64を2で割った余りは0(真)」なので, 真となります
- 5行目は, 「64は0より大きい(真)」または「64を2で割った余りは1(偽)」なので, 真となります
my $small = 10;
my $medium = 20;
my $large = 30;
if ( $small < $medium && $medium < $large ) {
print "小さい順に並んでます\n";
}
$small < $medium < $large
のように3つ以上の値を同時に比較することはできません$small < $medium
かつ$medium < $large
と同じ意味なので、関係演算子を使って比較することができます
#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 10; # 好きな値を入力しておく
- 簡単な数当てゲーム
question_num.pl
を作成しよう - 端末から数字を一つ入力し, その数字が
$answer
と一致したらOK
,$answer
より大きければtoo big
, 小さければtoo small
と表示します- オプション: 入力した値が,
$answer
から-5〜+5の範囲内(例えば,$answer
が10なら, 5〜15)の場合,near
と表示するようにしてみましょう(時間に余裕があれば, チャレンジしてみてください!)
- オプション: 入力した値が,
my @array = ( 1, "foo", 3 );
print "@array\n"; #=> 1 foo 3
- 配列を使うことで, 数値や文字列をまとめて格納できます
=
演算子を使うことで, 左辺の配列に右辺の値を代入することができます- 配列は変数名の前に
@
をつけます@
はアレイ(array)
のa
, と覚えるとよいでしょう
- 1行目の右側,
( ... )
の部分をリストと呼びます
my @array = ( 1, "foo", 3 );
print "$array[0]\n"; #=> 1
print "$array[1]\n"; #=> foo
print "$array[2]\n"; #=> 3
- 配列の一つ一つの要素にアクセスする場合は
$変数名[添字]
を使います- 添字は1ではなく0からスタートして, 1ずつ増えます
my @array = ( 1, "foo", 3 );
print "$array[0]\n"; #=> 1
- 配列に格納された, ある要素を取得する方法が
@変数名[添字]
ではなく$変数名[添字]
となっているのは, 「配列に格納された1つの要素」がスカラ(1つ)のデータであるためです
my @array = ( 1, "foo", 3 );
my $i = 1;
print "$array[$i]\n"; #=> "foo"
- 配列の添字には, 数字が入ったスカラー変数を置くこともできます.
my @array = ( 1, "foo", 3 );
$array[0] = "bar"; #=> ( "bar", "foo", 3 )
- 配列に新たな要素を代入する際は, 取り出すときと同様に添字を使います
my @array = ( 1, "foo", 3 );
my $sum = $array[0] + $array[2];
print "$sum\n" #=> 4
- 配列の要素は普通のスカラ変数と同じように扱えるので, このような計算もできます
my @array = ( 1, "foo", 3 );
print scalar @array; #=> 3
print $#array; #=> 2
- 配列を
scalar
演算子に与えると, 配列に格納されている要素の個数を取得できます @array
に対して$#array
と書くことで, 配列に格納されている最後の要素の添字を取得できます
my @array1 = ( 1, 2 );
my @array2 = ( 1 .. 5 );
my @array3 = ( @array1, 3 ); #=> (1, 2, 3)
()
を使うことで, 配列にまとめて値を代入することができます- 連続する数字であれば, 範囲演算子
..
を使って1 .. 5
と書くことで,1以上5以下
の値を配列に代入できます- ただし, 必ず右側の値が左側の値より大きくなければなりません.
@array2 = ( 5 .. 1 );
のように書くと@array2
には空の要素が格納されるので注意しましょう
- ただし, 必ず右側の値が左側の値より大きくなければなりません.
- 3行目のように, 数値や文字列だけでなく, 配列を代入することもできます
my @array = ( 1, "foo", 3 );
for my $foo ( @array ) {
print "$foo\n";
}
- 配列の中身を出力する方法として,
for
文がありますforeach
と書いても問題ありません. 実はPerlの内部では, 同じように処理されます
- この場合, 変数
$foo
に$array[0]
,$array[1]
... という値が順番に代入され, 処理が行われます
- 配列
@array
に好きな数値や文字列を設定し、for文で出力してください。 <STDIN>
を用いて配列@array2
に好きな数値や文字列を入力し、for文で出力してください。
2つの入力値を得る場合、配列の要素として <STDIN>
を直接書くことはできません。1つずつスカラー変数で受け取り、chomp
をした後で配列に入れましょう。
FizzBuzz
問題にチャレンジ!!- 1から100までの数字について, 以下のようなルールに従って表示を行う
fizzbuzz.pl
を作成しよう!- その数字が
3
で割り切れるならFizz
5
で割り切れるならBuzz
3
でも5
でも割り切れるならFizzBuzz
3
でも5
でも割り切れないならその数字
- その数字が
- 1から100までの数字について, 以下のようなルールに従って表示を行う
my @array = qw( Alice Bob Chris );
#=> ('Alice', 'Bob', 'Chris')
- これまでのリストの書き方
('this', 'is', 'list', 1, 2, 3)
と異なり、クォート記号が不要です。 - この記法では空白文字 (スペース、タブ、改行など) が無視され、残ったものがリストの要素になります。
my @arary = qw(
Alice
Bob
);
- なので、こういう書き方もできます。
qw! Alice Bob !
qw# Alice Bob #
qw/ Alice Bob /
デリミタ (区切り文字) には任意の記号文字を使えます。
これらは前述の
qw( Alice Bob )
と等しくなります。
このような問題に遭遇したとき、
qw/http://www.perl-entrance.org http://www.yahoo.com/
# エラーになってしまう!
# デリミタがスラッシュ (/) で
# 要素にもスラッシュが含まれているため
解決法は2つ。
# 1. 要素内のスラッシュをバックスラッシュでエスケープする
# => 読みにくく感じるかもしれない
qw/ http:\/\/www.perl-entrance.org http:\/\/www.yahoo.com /
# 2. デリミタを変える
# => ちょっと読みやすいかもしれない
qw! http://www.perl-entrance.org http://www.yahoo.com !
配列には便利な関数があります。「関数」とは、ある働きをもつ「機能」のことだと思ってください。ここではその一部を紹介します。
- split
- join
join は分割された文字列をくっつけて、1つの文字列にします。
my @words = qw( I Love Perl. ); # qwショートカット
my $poem = join '_', @words;
print $poem; # => 'I_Love_Perl.'
- join が受け取る第1引数 (上の例ではアンダースコア) は、リストの要素をくっつける糊のような役割を果たします。
- 第2引数には、対象の配列を渡します。
split は指定したパターンに従って文字列を分割します。
my $poem = 'I Love Perl.';
my @words = split / /, $poem; #=> ('I', 'Love', 'Perl.')
- 引数として与えた文字列を、 // でくくった文字 (上の例では半角スペース) で分割して配列に格納します。
- // は正規表現リテラルと呼ばれるものです。正規表現については次回以降に詳しく説明します。
- 次の処理をする
join.pl
を作りましょう。("0120", "123", "XXX")
という配列を作ってください。- 1の配列をjoin関数で連結してください。
電話番号っぽいので、ハイフン ('-') でくっつけてみましょう。
- 次の処理をする
split.pl
を作りましょう。- "There's more than one way to do it." という文字列を作り、split関数で" "(半角スペース)ごとに分割して配列
@array
に格納し、出力してください。 - 好きな文字列を作り、好きな要素で区切って配列
@array2
に格納し、出力してください。- 日本語や数字を混ぜてもよいでしょう。
- わからないところがあれば、サポーターに聞いてみましょう!
- "There's more than one way to do it." という文字列を作り、split関数で" "(半角スペース)ごとに分割して配列
- practice.md
- 今回の内容を復習することができる問題集です
- ご不明な点があれば, 気軽にスタッフまでお尋ねください
-
- 各会場の講師が書いた, 練習問題の解答例はこちらで公開しています
- ※講義終了後に随時追加していきます
-
- 昨年分の解答例はこちらで公開しています
- その他、本編で紹介しきれなかった内容を補足します。
- 本編でも説明したとおり,
$#array
は@array
の最後の添字を表します- この場合,
@array
には3個の要素が格納されているので,$#array
は2となります
- この場合,
- この性質を応用して, 以下のように書くことができます
my @array = ( 1, "foo", 3 );
for my $i (0 .. ($#array)) {
print "$array[$i]\n";
}
my @array = ( 1, "foo", 3 );
for ( my $i = 0; $i < scalar(@array); $i++ ) {
print "$array[$i]\n";
}
scalar(@array)
は,@array
の要素数を表します -この場合,@array
には3個の要素が格納されているので,scalar(@array)
は3となります- 最近のPerlプログラムでは, このC言語風や前述の
$#array
までの添字指定のfor
はあまり使われなくなっているようです.- 講義で最初に解説したforループが簡潔で, 多くの要望を満たすことができます.
my @array = (1, "foo", 3);
my $i = 0;
while ( $i < scalar(@array) ) {
print "$array[$i]\n";
$i++;
}
- whileループを使って, forループと同じように繰り返し処理ができます
- whileの()の中には、繰り返しを行うための条件を書きます
- forループでもwhileループでも同じ処理は書けますが、それぞれ適している・好まれるケースがあります
- forループは配列全てに対して処理を行う時など、繰り返す回数が決まっている場合に好まれる書き方です
- whileループは繰り返す回数は決まっていないが、特定の条件が真の間ずっと処理を繰り返したいときに好まれる書き方です