Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time

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ループで大抵事足りるためです