Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.

Latest commit

 

History

History
623 lines (485 loc) · 22.3 KB

slide.md

File metadata and controls

623 lines (485 loc) · 22.3 KB

Perl入学式 #2


今日の流れ

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

前回の復習


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 -> 望ましくない記述を警告してくれる効果があります
    • 以下, この資料のサンプルコードではこれを「お約束」として省略します
    • 書かれているものとして扱ってください

復習問題

  • 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のように intcharといった「型」がないので, 数値や文字列などを自由に代入することができます

仮の変数名

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では, #より後ろの文字列は全てコメントとして扱われます
    • コメントは, 実行されません
    • この資料の中で, コメントを使ってコードに補足を行うことがあります

練習問題 (profile.pl)

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

標準入力


標準入力

  • 標準入力(Standard Input)とは、プログラムに入ってくるデータです
    • 通常, キーボードから入力されるテキストデータのことを指します
  • Perlでは, この「標準入力」をプログラムの中で<STDIN>と表現します

標準入力

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

標準入力

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

四則演算


基本的な演算子(四則演算)

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 -= $bar;
--$bar;  # または $bar--
# すべて「2 - 1 = 1」
  • 「1」ずつ加減したい場合は上記のように記述できます
  • 「1」ずつ加算することを「インクリメント」, 減算することを「デクリメント」といいます

基本的な演算子(文字列連結)

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

演算の順番

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

練習問題 (calc.pl)

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

if, else文


制御構文(if)

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

よくあるまちがい (1)

my $foo == 1; # まちがい

my $bar =  1; # せいかい
  • 代入の=と, 数値の比較の==をよく間違えます
    • この場合, 実行するとUse of uninitialized value $foo in numeric eq (==)のようなエラーになります

よくあるまちがい (2)

my $foo = 1;
if ($foo =  2) { ... } # まちがい
if ($foo == 2) { ... } # せいかい
  • 数値の比較の==と, 代入の=をよく間違えます
    • この場合, 実行するとFound = in conditional, should be ==のような警告が出ます

制御構文(if)

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

数値の比較演算子

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

文字列の比較演算子

eq  ==  equal
ne  !=  not equal
gt  >   greater than
ge  >=  greater equal
lt  <   less than
le  <=  less equal
  • 数値を比較する場合は==!=を使いますが, 文字列を比較する場合はeqneといった演算子を使います
    • もっとも, 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」という文字列が出力されます

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

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

Perlにおける真偽値

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

複数の制御構文

my $foo = 1;
if ( $foo == 1 ) {
    ...
} elsif ( $foo == 2 ) {
    ...
} elsif ( $foo == 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 $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(偽)」なので, 真となります

練習問題(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, "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 );
$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行目のように, 数値や文字列だけでなく, 配列を代入することもできます

for ループ

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

練習問題(for.pl)

  1. 配列@arrayに好きな数値や文字列を設定し、for文で出力してください。
  2. <STDIN>を用いて配列@array2に好きな数値や文字列を入力し、for文で出力してください。

練習問題(fizzbuzz.pl)

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

qw ショートカット

my @array = qw( Alice Bob Chris );
    #=> ('Alice', 'Bob', 'Chris')
  • これまでのリストの書き方 ('this', 'is', 'list', 1, 2, 3) と異なり、クォート記号が不要です。
  • この記法では空白文字 (スペース、タブ、改行など) が無視され、残ったものがリストの要素になります。

qw ショートカット

  • なので、こういう書き方もできます。

    my @arary = qw( Alice Bob );


qw ショートカット

qw! Alice Bob !
qw# Alice Bob #
qw/ Alice Bob /

デリミタ (区切り文字) には任意の記号文字を使えます。
これらは前述の

qw( Alice Bob )

と等しくなります。


qw ショートカット

このような問題に遭遇したとき、

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 !

配列の関数(1)

配列には便利な関数があります。「関数」とは、ある働きをもつ「機能」のことだと思ってください。ここではその一部を紹介します。

  • split
  • join

join

join は分割された文字列をくっつけて、1つの文字列にします。

my @words = qw( I Love Perl. ); # qwショートカット
my $poem  = join '_', @words;
print $poem;  # => 'I_Love_Perl.'
  • join が受け取る第1引数 (上の例ではアンダースコア) は、リストの要素をくっつける糊のような役割を果たします。
  • 第2引数には、対象の配列を渡します。

split

split は指定したパターンに従って文字列を分割します。

my $poem  = 'I Love Perl.';
my @words = split / /, $poem; #=> ('I', 'Love', 'Perl.')
  • 引数として与えた文字列を、 // でくくった文字 (上の例では半角スペース) で分割して配列に格納します。
  • // は正規表現リテラルと呼ばれるものです。正規表現については次回以降に詳しく説明します。

練習問題 (1/2)

  • 次の処理をする join.pl を作りましょう。
    1. ("0120", "123", "XXX") という配列を作ってください。
    2. 1の配列をjoin関数で連結してください。
      電話番号っぽいので、ハイフン ('-') でくっつけてみましょう。

練習問題 (2/2)

  • 次の処理をする split.pl を作りましょう。
    1. "There's more than one way to do it." という文字列を作り、split関数で" "(半角スペース)ごとに分割して配列 @array に格納し、出力してください。
    2. 好きな文字列を作り、好きな要素で区切って配列 @array2 に格納し、出力してください。
      • 日本語や数字を混ぜてもよいでしょう。
      • わからないところがあれば、サポーターに聞いてみましょう!

復習問題

  • practice.md
    • 今回の内容を復習することができる問題集です
    • ご不明な点があれば, 気軽にスタッフまでお尋ねください

練習問題の解答例

  • 2016-answer

    • 各会場の講師が書いた, 練習問題の解答例はこちらで公開しています
    • ※講義終了後に随時追加していきます
  • 2015-answer

    • 昨年分の解答例はこちらで公開しています

落ち穂拾い

  • その他、本編で紹介しきれなかった内容を補足します。

for ループ ( 応用 )

  • 本編でも説明したとおり, $#array@arrayの最後の添字を表します

    • この場合, @arrayには3個の要素が格納されているので, $#arrayは2となります
  • この性質を応用して, 以下のように書くことができます

    my @array = ( 1, "foo", 3 ); for my $i (0 .. ($#array)) { print "$array[$i]\n"; }


for ループ ( C言語風 )

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となります
  • もっとも, よほどの事がないかぎり, この方式のforは使いません!
    • 先ほど紹介したforループで大抵事足りるためです