Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
515 lines (405 sloc) 17.8 KB

Perl入学式 #2


今日の流れ

  • 前回の復習
  • おまじない
  • 変数
  • 標準入力
  • 四則演算
  • 基本的な演算子
  • if, else文
  • 論理演算子
  • for文, 配列

前回の復習


plenv

$ plenv versions
* 5.20.2
  system
  • plenv versionsとすることで, 5.20.2が選択されているか確認してみよう
    • 選択されていなければ, plenv global 5.20.2 と実行しよう

Hello, World!

print "Hello, World!\n";
  • このように書いたものを, hello.plとして保存します
  • printは, 端末に文字を出力します
  • \nは改行を表します
  • 最後に;を忘れずに!

Hello, World! の実行

$ perl hello.pl
Hello, World!
  • perlの引数に実行するスクリプトファイル名を与えると, そのスクリプトを実行します

おまじない


おまじない

#!/usr/bin/env perl
use strict;
use warnings;
  • おまじないとして, 冒頭の3行を書くようにしよう
  • use strict -> 厳密な書式を定めたり, 未定義の変数を警告するといった効果があります
  • use warnings -> 望ましくない記述を警告してくれる効果があります
    • 以下, この資料のサンプルコードでは「お約束」を省略します
    • 書かれているものとして扱ってください

use

use Acme::FizzBuzz;
  • use の後にモジュール名を書くことで, そのモジュールを読み込んで利用する事を意味します
  • 前回の Acme::FizzBuzz のように, http://www.cpan.org/ からモジュールを入手できます
    • Perl インストール時にデフォルトで入っているモジュールもあります

練習問題 (hello.pl)

  • 先程の冒頭の3行のおまじないを加えた上で, Hello, Worldという文字列を出力するhello.plを作成しよう
    • ヒント: 文字列は"で囲みます
    • ヒント: 文字列を出力する関数はprintです

変数


変数とは?

  • 「変数」は, いわば「データを格納できる箱」です
    • Perlの変数には, 「スカラ変数」, 「配列」, 「連想配列(ハッシュ)」という3つの種類があります
  • 「スカラ変数」は, 「1つの要素しか入らない箱」と思って下さい
  • 「配列」と「連想配列(ハッシュ)」は, 「複数の要素を格納出来る箱」と思って下さい
  • まずは, 1つの要素を格納できる「スカラ変数」について見て行きましょう

スカラ変数

my $hoge;
$hoge = 1;
my $foo = 3.14;
$hoge = "bar";
  • スカラ変数の先頭には, $hogeのように$をつけます
    • $スカラ(scalar)S, と覚えるとよいでしょう
  • =演算子を使うことで, 左辺のスカラー変数に右辺の値を入れる(代入する)ことができます
  • 変数を宣言するとき(初めて使うとき)は, 先頭にmy をつけます
  • Perl では, C言語やJavaのように intcharといった型がないので, 数値や文字列などを自由に代入することができます

変数の出力

my $hoge = 1;
print "$hoge\n"; # => 1
print '$hoge\n'; # => $hoge\n
  • print を使うことで変数を出力することができます
  • 変数を出力する場合は, ""(ダブルクォテーション)の中に変数を書きましょう
    • ""の中に変数を書くと, その変数の中身が展開されて表示されます
    • ''の中では, 展開はされず, 全てがそのまま出力されます
      • 変数だけでなく, \nなどもそのまま出力されます!
  • \nは改行を意味します

練習問題 (profile.pl)

  • 自分の名前, 年齢, 身長などの情報をそれぞれname, age, heightといったスカラ変数に格納し, それらの値を出力するスクリプト profile.plを作成しよう
  • 「お約束」の3行を忘れずに!

標準入力


標準入力

my $str = <STDIN>;
chomp $str;
print $str;
  • 端末からPerlに対して, 標準入力を使って文字列を入力することができます
    • 1行目では, <STDIN>で端末から文字列を入力し, 入力された文字列を変数strに代入しています
    • 2行目では, chompで行末の改行を削除しています

標準入力

print 'input > ';
my $str = <STDIN>;
chomp $str;
print $str . "\n";
  • このコードを動かしてみます
    • <STDIN>がどのような働きをするか見てみましょう

四則演算


基本的な演算子

my $hoge = 4;
my $foo  = 2;
my $res;
$res = $hoge + $foo;  # 4 + 2 = 6
$res = $hoge - $foo;  # 4 - 2 = 2
$res = $hoge * $foo;  # 4 * 2 = 8
$res = $hoge / $foo;  # 4 / 2 = 2
$res = $hoge % $foo;  # 4 % 2 = 0
$res = $hoge ** $foo; # 4 の 2乗 は 16
  • perlでは, C言語と異なりべき乗の計算を簡単に行うことができます

インクリメント/デクリメント

my $num = 0;
$num++;
print $num; # 1

my $num = 10;
$num--;
print $num; #9
  • ++で1を足したり--で1を引いたりすることができます

演算の順番

my $hoge = 2 + 4 * 3;   # 14
my $fuga = (2 + 4) * 3; # 18
  • 演算の順序は, ()を付けることで変更することができます
    • 通常の数学と同じく, Perlも足し算・引き算より掛け算・割り算の優先順位が高いです
    • しかし, 2行目では()を付けることで足し算を先に計算させています

文字列連結

my $foo = 'hoge';
my $bar = 123;
my $baz = $foo . $bar; # hoge123
print $foo . $baz . "\n"; # hogehoge123
  • .で, 文字列や変数を連結することができます

練習問題 (calc.pl)

1 + 2 = 3
1 - 2 = -1
1 * 2 = 2
1 / 2 = 0.5
  • 標準入力<STDIN>から0以外の整数を2つ読み込み, それらを四則演算(+, -, *, /)した結果を上の例のように出力するスクリプト calc.plを作成しよう

if, else文


制御構文(if)

my $hoge = 1;
if ( $hoge == 1 ) {
  print "OK\n"; # 条件が「真」の場合
} else {
  print "NG\n"; # 条件が「偽」の場合
}
  • == は"右辺と左辺が等しければ真"であることを意味します
    • 真 = 条件が正しい, 偽 = 条件が正しくない
  • ここでは$hoge1と等しい場合に限り真となり, OKという文字が表示されます
  • $hogeが1でなければ, 偽となるためelseに処理が移りNGという文字が表示されます

制御構文(if)

my $hoge = 1;
if ( $hoge == 1 ) {
  print "OK\n"; # 条件が「真」の場合
}
  • elseの部分は省略することもできます
    • この場合, 条件が偽の場合($hoge1ではない場合)は, 何の処理も行われません

数値の比較演算子

== # 右辺と左辺が等しいならば真
!= # 右辺と左辺が等しくないならば真
<  # 右辺より左辺が小さいならば真
>  # 右辺より左辺が大きいならば真
<= # 右辺が左辺以上ならば真
>= # 右辺が左辺以下ならば真
  • 数字同士を比較するときは, このような比較演算子を使います

文字列の比較演算子

eq  ==  equal
ne  !=  not equal
gt  >   greater than
ge  >=  greater equal
lt  <   less than
le  <=  less equal
  • 数値を比較する場合は==!=を使うが, 文字列を比較する場合はeqneといった演算子を使います
    • もっとも, eq, ne以外はあまり使いません
    • 文字列の大小とは, 辞書順に並べた時に前にくるものが小さく, 後ろにくるものが大きいということです

文字列比較

my $hoge = 'hello';
if ( $hoge eq 'hello' ) {
    print "OK";
} else {
    print "NG";
}
  • 今回は文字列を比較しているので, ==ではなくeqを用いています

数値の比較と文字列の比較

if ('42strings' == 42) {
  print "OK\n";
}
  • use warningsが有効であれば, 文字列を数値用の比較演算子で比較しようとすると, 次のような警告を出力します
    • Argument "42strings" isn't numeric in numeric eq (==) at reply input line 1.
  • このような場合, Perlは文字列を無理やり数値として解釈して処理を継続します
    • この場合, '42strings'には先頭に42という数値が含まれているので, Perlは==の演算子の左辺は42として処理を実行します
    • そのため, この比較は真となり, 「OK」という文字列が出力されます

数値の比較と文字列の比較

if ('42' eq 42) {
  print "OK\n";
}
  • 逆に, 文字列の比較演算子で数値を比較しようとした場合, 警告は出力されません
    • Perlは自動的に数値を文字列として解釈して, eq演算子の右辺は'42'として扱われます
    • そのため, この比較は真となり, 「OK」という文字列が出力されます

Perlにおける真偽値

  • Perlには, truefalseなどで真偽値を表すことはできません
  • そのかわりPerlでは, 次の5つの値が「偽」の値(偽値)として扱われます
    • 数値「0」
    • 文字列「'0'」と「''」
    • 空のリスト「( )」
    • undef
  • そしてこれ以外の値は, Perlでは全て真として扱われます

複数の制御構文

my $hoge = 1;
if ( $hoge == 1 ) {
    ...
} elsif ( $hoge == 2 ) {
    ...
} elsif ( $hoge == 3 ) {
    ...
} else {
    ...
}
  • elsifを使うことで, 分岐条件をさらに増やすことができます
    • PerlにはC言語のswitchにあたるものはないので, if/elsif/elseで代用しましょう

練習問題(question_word.pl)

#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 'perl'; # 好きな文字を入力しておく
  • 簡単な文字当てゲーム question_word.plを作成しよう
  • 端末から文字列を一つ入力し, その文字列が$answerと一致したらOK, 外れたらNGと表示します

論理演算子


関係演算子

&& -> かつ
|| -> または
  • if文で複雑な条件を扱いたいときは, 関係演算子を用いて複数の条件を連結しましょう
    • &&演算子は「かつ」なので, 両方の条件が真となるときのみ真となります
    • ||演算子は「または」なので, 条件のどちらか1つでも真となるならば真となります

関係演算子

my $hoge = 64;
if ( $hoge > 0 && $hoge % 2 == 0 ) {
    print "&&: OK\n";
}
if ( $hoge > 0 || $hoge % 2 == 1 ) {
    print "||: OK\n";
}
  • 2行目は, 「64は0より大きい(真)」かつ「64を2で割った余りは0(真)」なので, 真となります
  • 5行目は, 「64は0より大きい(真)」または「64を2で割った余りは1(偽)」なので, 真となります

練習問題(question_num.pl)

#!/usr/bin/env perl
use strict;
use warnings;
my $answer = 1; # 好きな値を入力しておく
  • 簡単な数当てゲーム question_num.plを作成しよう
  • 端末から数字を一つ入力し, その数字が$answerと一致したらOK, $answerより大きければtoo big, 小さければtoo smallと表示します
    • オプション: 入力した値が, $answerから-5〜+5の範囲内(例えば, $answerが10なら, 5〜15)の場合, nearと表示するようにしてみましょう

for文, 配列


配列

my @array = ( 1, "hoge", 3 );
print "@array\n";    # 1 hoge 3
  • 配列を使うことで, 数値や文字列をまとめて格納できます
  • =演算子を使うことで, 左辺の配列に右辺の値を代入することができます
  • 配列は変数名の前に@をつけます
    • @アレイ(array)a, と覚えるとよいでしょう
  • 1行目の右側, ( ... )の部分をリストと呼びます

配列

my @array = ( 1, "hoge", 3 );
print "$array[0]\n"; # 1
print "$array[1]\n"; # hoge
print "$array[2]\n"; # 3
  • 配列の一つ一つの要素にアクセスする場合は$変数名[添字]を使います
    • 添字は1ではなく0からスタートして, 1ずつ増えます

配列

my @array = ( 1, "hoge", 3 );
print "$array[0]\n"; # 1
  • 配列に格納された, ある要素を取得する方法が@変数名[添字]ではない理由は, 「配列に格納された1つの要素」はスカラ(1つ)のデータである為です
    • そのため, 先頭に@ではなく$が付きます

配列(計算)

my @array = ( 1, "hoge", 3 );
my $sum = $array[0] + $array[2];
print "$sum\n" # => 4
  • 配列の要素は普通のスカラ変数と同じように扱えるので, 代入や計算ができます

配列(代入)

my @array = ( 1, "hoge", 3 );
$array[1] = 10;
my $sum = $array[0] + $array[1] + $array[2];
print "$sum\n" # => 14
  • 配列の要素は普通のスカラ変数と同じように扱えるので, 代入や計算ができます

配列の要素数

my @array = ( 1, "hoge", 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以下の値を配列に代入できます
  • 3行目のように, 数値や文字列だけでなく, 配列も組み合わせることができます

reverse

my @array1 = ( 5, 4, 3, 2, 1 );
my @array2 = reverse ( 1 .. 5 ); # OK
my @array3 = ( 5 .. 1 ); # NG
  • @array1のように, 連番を逆の順番で配列に格納したい場合はreverseを使いましょう
    • 範囲演算子..は, 必ず右側の値が左側の値より大きくなければなりません
    • そのため, @array2 = ( 5 .. 1 );のように書くと@array2には空の要素が格納されるので注意しましょう

sort

my @array1 = ( 5, 4, 3, 2, 1 );
my @sorted = sort @array1; # (1, 2, 3, 4, 5)
  • sortを使うと, 配列の要素を並び替えることができます
    • sort { $a <=> $b } @arrayと書くと, 数値としてソートします
    • sort { $a cmp $b } @array, あるいはsortのみを書くと, 文字列としてソートします
  • 変数$a$bはsortで使う為に予約されているので, sort以外で使ってはいけません

for ループ

my @array = ( 1, "hoge", 3 );
for my $var ( @array ) {
  print "$var\n";
}
  • 配列の中身を走査するのに, for文があります
    • foreachと書いても問題ありません. 実はPerlの内部では, 同じように処理されます
  • この場合, 変数$var$array[0], $array[1] ... という値が順番に代入され, 処理が行われます

for ループ ( C言語風 )

my @array = ( 1, "hoge", 3 );
for ( my $i = 0; $i < scalar @array; $i++ ) {
  print "$array[$i]\n";
}
  • $#arrayは, @arrayの最大の添字を表します -この場合, @arrayには3個の要素が格納されているので, $#arrayは2となります
  • よほどの事がないかぎり, この方式のforは使いません!
    • 先ほど紹介したforループで大抵事足りる為です

for ループ ( 範囲演算子 )

my @array = ( 1, "hoge", 3 );
for my $i (0 .. ($#array)) {
  print "$array[$i]\n";
}
  • 先ほどのC言語風のforループは, 範囲演算子を利用してこのように記述することができます.
    • 結構便利なので覚えておきましょう!

練習問題(sort.pl)

  • 配列@array<STDIN>を使って3つの文字列を格納し, これを「文字列として」ソートしたものを出力するsort.plを書いてみよう
    • オプション: @arrayに文字列を3個入力する処理は, <STDIN>を3回書くのではなく, for文を使ってシンプルに書いてみよう

ヒント

  • プログラムの組み立て方を1つずつやってみましょう
    1. 文字列を受け取る部分を作ってみよう
    2. ソートする部分を作ってみよう
    3. 文字列を出力する部分を作ってみよう
    4. 文字列を受け取る部分をfor文に変更してみよう

最終問題(fizzbuzz.pl)

  • FizzBuzz問題にチャレンジ!!
    • 1から100までの数字について, 以下のようなルールに従って表示を行うfizzbuzz.plを作成しよう!
      • その数字が3で割り切れるならFizz
      • 5で割り切れるならBuzz
      • 3でも5でも割り切れるならFizzBuzz

復習問題


練習問題の解答例