Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
2 contributors

Users who have contributed to this file

@sironekotoro @xtetsuji
1256 lines (893 sloc) 36.7 KB

Perl入学式 第2回

構文基礎編


諸注意

  • 会場について

    • 飲食・喫煙・トイレetc
  • 写真撮影について

    • 写真撮影NGな方はお手数ですが申し出てください

    • 写真はPerl普及団体の JPA ( Japan Perl Association )への活動報告に利用します


講師紹介

  • 講師・サポーター紹介

皆さんで自己紹介

  • せっかく今日集まったので, テーブルで自己紹介をしましょう.

  • 話題は自由ですが, 以下がオススメです

    • 名前(ハンドルネーム)

    • なぜPerlを勉強してみようと思ったか

    • なぜPerl入学式に参加してみようと思ったか


今日の流れ

  • 前回の復習
  • 条件分岐( if文)
  • 比較演算子( <, >, ==, !=, eq, ne, gt, lt )
  • 論理演算子( &&, || )
  • 配列
  • 繰り返し( for文 )
  • 配列の操作( join, split, push, pop, shift, unshift, reverse, sort )
  • ハッシュ
  • ハッシュの操作( keys, delete, exsts )

前回の復習


ターミナルからディレクトリ操作

    $ 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

    • 望ましくない記述を警告する
  • 以下, この資料のサンプルコードでは紙面の都合上「おまじない」を省略しますが, 皆さんは必ず記述してください


Hello, World!(hello.pl)

    print "Hello, World!\n";
  • このように書いたものを, hello.pl として保存します

  • print は, ターミナルに文字を出力します

  • Hello, World! はダブルクォーテーション " " で囲みます

  • \n は改行を表します

  • 行の最後に ; を忘れずに!

  • そして「おまじない」の3行も忘れないこと!


Hello, World! の実行

    $ perl hello.pl

    Hello, World!
  1. ターミナルを開きます

  2. perl から1つスペースを空けて hello.pl と入力してenterキーを押します

    • プログラムに渡される情報, 値などを引数と言う

    • この例では hello.pl が引数にあたる

  3. プログラムの中に書いた Hello, World が表示されます


復習問題 (hello_perl.pl, calc.pl)

  1. Hello, Perl Entrance! という文字列を出力するスクリプト hello_perl.pl を書いて下さい

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

    1 + 2 = 3

    1 - 2 = -1

    1 * 2 = 2

    1 / 2 = 0.5

わからない所があれば, 近くのサポーターに聞きましょう!


if文


条件分岐

変数の状態に応じてスクリプトの動きを分岐させることを 条件分岐 といいます

条件分岐には様々なパターンがありますが、それらを , の2つの組み合わせで表現します

真, 偽 の判断に用いる式を 条件式 といいます


Perlにおける真偽値

Perlでは, 次の5つの値が「偽」の値として扱われます

  1. 数値「0

  2. 文字列「'0'

  3. 文字列「''」(シングルクォーテーションの連続, 間に何もない. 空文字ともいう)

  4. 空のリスト「()

  5. undef

そしてこれ以外の値は, Perlでは全て「真」として扱われます

明示的な「真」の値が必要な場合, 数値の 1 を使う場合が多いです


Perlにおける真偽値

他のプログラミング言語では, truefalse という単語に 真 , 偽 の意味を持つキーワードとして扱われることが多いです

しかし, Perlは, truefalse などで真偽値を表すことはできず, また特別な意味もありません


if文

    if ( 1 ) {           # 明示的な「真」の値である 1

        print "OK\n";    # 条件が「真」なので出力される

    }
    if ( 0 ) {           # 「偽」の値である 0

        print "OK\n";    # 条件が「偽」なので出力されない

    }

数値の比較演算子

    == # 右辺と左辺が等しいならば「真」

    != # 右辺と左辺が等しくないならば「真」

    <  # 右辺より左辺が小さいならば「真」

    >  # 右辺より左辺が大きいならば「真」

    <= # 右辺が左辺以上ならば「真」

    >= # 右辺が左辺以下ならば「真」

数値同士を比較するときは, このような記号を用いた比較演算子を使います


数値を使った条件分岐

    my $foo = 1;

    if ( $foo == 1 ) {
        print "OK\n"; # 条件が「真」の場合
    }
    else {
        print "NG\n"; # 条件が「偽」の場合
    }

( ) の中の $foo == 1 が条件式です

==右辺と左辺が数値として等しければ真 であることを意味します

ここでは $foo1 と等しい場合に「真」となり, OK という文字が表示されます

$foo1 と等しくない場合は, 「偽」となり, else に処理が移って NG という文字が表示されます


よくあるまちがい (1)

    my $foo == 1; # NG

    my $bar =  1; # OK

数値の比較に用いる == と, 代入の = を間違えています

この場合, 実行すると以下のエラーが出ます

Useless use of numeric eq (==) in void context

「おまじない」の3行を忘れた場合はエラーが出ずに危険です


よくあるまちがい (2)

    my $foo = 1;

    if ($foo =  1) { print $foo } # NG

    if ($foo == 1) { print $foo } # OK

条件式に注目してください

代入の = と, 数値の比較に用いる == を間違えています

この場合, 実行すると以下のエラーが出ます

Found = in conditional, should be ==

「おまじない」の3行を忘れた場合はエラーが出ずに危険です


文字列の比較演算子

    eq  # equal

    ne  # not equal

    gt  # greater than

    ge  # greater equal

    lt  # less than

    le  # less equal

文字列を比較する場合はeqneといった単語を用いた比較演算子を使います

「文字列の大小」とは, 文字列の長さではありません

辞書順に並べた時に前にくるものが小さく, 後ろにくるものが大きいという意味です


文字列を使った条件分岐

    my $foo = 'hello';

    if ( $foo eq 'hello' ) {
        print "OK\n";   # 文字列が等しいので OK と表示される
    }
    else {
        print "NG\n";
    }

文字列を比較しているので, == ではなく eqを用いています


練習問題(question_word.pl)

    #!/usr/bin/env perl
    use strict;
    use warnings;
    my $answer = 'perl';    # 好きな文字を入力しておく

簡単な文字当てゲーム question_word.plを作成しよう

  1. ターミナルから, 標準入力で文字列を一つ入力します

  2. その文字列が $answer と一致したらOKと表示します

  3. 外れたら 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 から == に変更すると, 先ほどとは逆の結果となります.

== は数値を比較するときに使う比較演算子です

このため、条件式の左辺・右辺は数値として 等しい と判断されます


複数の条件分岐

    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";
    }
  • elsifを使うことで, 分岐条件を増やすことができます

  • else if ではなく, elsif です


論理演算子


論理演算子 AND, OR

    && # かつ

    || # または

if文で複雑な条件を扱いたいときは, 論理演算子を用いて複数の条件を連結します

  • && 演算子は「かつ・AND」の意味を持ち, 両辺の条件が真となるときのみ真となる

  • || 演算子は「または・OR」の意味を持ち, 条件の片方1つでも真ならば真となる


論理演算子 AND, OR

    my $foo = 10;

    if ( $foo > 0 && $foo % 2 == 0 ) {  # $fooが 0 より大きい かつ 2 で割り切れる
        print "&&: OK\n";    # &&: OK
    }
    else{
        print "&&: NG\n"
    }

条件式の中の $foo > 0 && $foo % 2 == 0 が 真 となり, OK と表示されます

  1. $foo が 0 より大きいので, $foo > 0 を満たす

  2. $foo を 2 で割った剰余は 0 なので, $foo % 2 == 0 も満たす

  3. 「1. かつ 2. が 真」の条件を満たすので条件式は 真 となり、&&: OK と表示される


論理演算子 AND, OR

    my $foo = 10;

    if ( $foo > 0 || $foo % 2 == 1 ) {  # $fooが 0 より大きい または 2 で割り切れない
        print "||: OK\n";    # ||: OK
    }
    else{
        print "&&: NG\n"
    }

条件式の中の $foo > 0 || $foo % 2 == 1 が 真 となり, ||: OK と表示されます

  1. $foo が 0 より大きいので, $foo > 0 を満たす

  2. 「1. または 2. が 真」の条件のうち、「1. が 真 」を満たすので条件式は 真 となり、||: OK と表示される


3つ以上の値を比較したい場合

    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 <"

3つ以上の値を比較したい場合

    my $small  = 10;
    my $medium = 20;
    my $large  = 30;

    if ( $small < $medium && $medium < $large ) {
        print "小さい順に並んでます\n";
    }

$small < $medium かつ $medium < $large というように, 関係演算子を使って比較します


練習問題(question_num.pl)

    #!/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と表示する


配列


配列

    my @array = ( 1, "foo", 3 );

1行目の右辺, ( 1, "foo", 3 ) の部分を リスト と呼びます

このリストをPerlで操作するために 配列変数 に格納します

配列に含まれる 1, "foo", 3 それぞれを 要素 といいます

スカラー変数と同様に = 演算子を使うことで, 左辺の配列に右辺のリストを代入することができます

配列は変数名の前に@をつけます. @アレイ(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つだけなのでスカラー変数となる ためです

  • スカラ変数:1つの要素を格納できる
  • 配列、ハッシュ:複数の要素を格納できる (第1回Part4より)
  • 配列から複数の要素を取り出すときには配列スライスを利用します. この時のシジルは @ になります. が, 時間の都合上説明はしません

配列要素の添字

    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";       #bar foo 3

配列に新たな要素を代入する際は, 取り出すときと同様に添字を使います

配列に, 配列を代入することもできます

    my @array_one_two = ( 1, 2 );
    my @array_numbers = ( @array_one_two, 3 );
    print "@array_numbers";    # 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";    # 1 2 3 4 5
  • 連続する数字は範囲演算子 .. が便利です.

  • 1 .. 5 と書くことで, 1 から 5 までの連続する値を配列に代入できます

  • ただし, 必ず右側の値が左側の値より大きくなければなりません.

    my @array2 = ( 5 .. 1 );
    print "@array2\n";              # (何も表示されない)
    print scalar @array2 . "\n";    # 0

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 ショートカットと範囲演算子

my @array = qw(1 .. 50);
print @array;    # 1..50

qwショートカットと範囲演算子は同時に利用することができません


繰り返し( for文 )


for ループ

    my @array = ( 1, "foo", 3 );
    for my $element (@array) {
        print "$element\n";
    }

配列の中身を順番に処理する方法として, for文 があります

foreach と書いてもPerlの内部では同じように処理されます

この場合, 変数 $element に 配列の先頭から順番に $array[0] , $array[1], $array[2] とスカラー値が順番に代入され, 処理が行われます


forループと範囲演算子

    for my $i ( 1 .. 50 ) {
        print "$i\n";    # 1 から 50 まで 1つずつ改行されて表示される
    }

配列のところで学習した範囲演算子 .. を利用することで, 決まった回数分だけ処理を繰り返したいときに利用できます.

    for my $i ( 1 .. 50 ) {
        print "Hello, World\n";    # Hello, World が 50回表示される
    }

練習問題(for.pl)

  1. 配列 @array に好きな数値や文字列を設定し, for文で出力してください。

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

    • 2つの入力値を得る場合, 配列の要素として <STDIN> を直接書くことはできません

      my @array = ( <STDIN>, <STDIN> );    # NG
    • 1つずつスカラー変数で受け取り, chomp をした後で配列に入れましょう


練習問題(even.pl)

  • for文を使って 1 から 100 までを出力してみましょう

  • 次に 1 から 100 までのうち, 偶数のみを出力するようにプログラムを変えてみましょう

    • ヒント: Perlでは計算の剰余を求める % 演算子があります

    • 例えば 5 % 35 / 3の余りですので,2 が求まります


練習問題(fizzbuzz.pl)

1から100までの数字について, 以下のようなルールに従って表示を行う fizzbuzz.pl を作成しよう!

  • その数字が 3 で割り切れるなら Fizz と表示する

  • 5 で割り切れるなら Buzz と表示する

  • 3 でも 5 でも割り切れるなら FizzBuzz

  • 3 でも 5 でも割り切れないならその数字

コンピュータサイエンス学科卒業生の過半数にはそれ(fizzbuzz)ができないのだ
()部はsironekotoro追加

参考:[どうしてプログラマに・・・プログラムが書けないのか?](http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm)

配列の関数


配列の関数 join, split

関数 とは, ある働きをもつ機能のことです

いままで変数の中身を表示してきた print も関数です

まずは2つ紹介します

  • join

  • split


join

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

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

  • 第2引数には, 対象の配列を渡します

プログラムに渡される情報, 値などを 引数 と言います

(第2回 冒頭)

split

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

    my $poem = 'I_Love_Perl.';
    my @words = split /_/, $poem;    # ('I', 'Love', 'Perl.')
    print "@words\n";

split が受け取る第1引数 (上の例ではアンダースコア) は, 文字列を分割する区切りのような役割を果たします

第2引数には, 対象の文字列を渡します

/ / は正規表現リテラルと呼ばれるものです.

正規表現については第3回で詳しく説明します


練習問題 (1/2)

次の処理をする join.pl を作りましょう。

  1. ("0120", "123", "XXX") という配列を作ってください

  2. 作成した配列をjoin関数を利用して - で連結して表示してください.


練習問題 (2/2)

次の処理をする split.pl を作りましょう。

  • "There's more than one way to do it." という文字列を作り, split関数で " "(半角スペース)ごとに分割して配列 @array に格納し, 出力してください。

  • 好きな文字列を作り, 好きな要素で区切って配列 @array2 に格納し, 出力してください. 日本語や数字を混ぜてもよいでしょう。


配列の関数 push, pop, unshift, shift

さきほど、皆さんは配列の基本を勉強しました。

配列の用途は主に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 を利用します


練習問題 (1/2)

次の処理をする array_pop_shift.pl を作りましょう。

  1. ('Alice', 'Bob', 'Chris') という配列 @array を作ってください

  2. 配列 @array から 'Chris' を取り出し、出力してください

  3. 配列 @array から 'Alice' を取り出し、出力してください


練習問題 (2/2)

次の処理をする array_push_unshift.pl を作りましょう。

  1. ('Alice', 'Bob', 'Chris') という配列 @array を作ってください。

  2. 配列 @array の末尾に Diana を追加し、 ('Alice', 'Bob', 'Chris', 'Diana') という配列を作ってください。

  3. 配列 @array の最初に Eve を追加し、 ('Eve', 'Alice', 'Bob', 'Chris', 'Diana') という配列を作ってください。

  4. 配列をfor文で出力してみましょう。


配列の関数 reverse

reverse はリストを逆順に並べ替えて、そのリストを返します。

    my @lang     = qw(perl php ruby python java go);
    my @reversed = reverse @lang;
    print "@reversed";    # go java python ruby php perl

配列の関数 reverse

連番を逆順で配列に格納したいとき, qwショートカットと組み合わせると便利です

    my @array = reverse( 1 .. 5 );

    print "@array\n";    # 5 4 3 2 1

配列の関数 sort

sort は配列をルール順に並べ替えて、その配列を返します。

sortのみ, あるいは sort { $a cmp $b } @array と書くと, 「文字列」として昇順に(aからzへ)ソートします

    my @lang        = qw(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

「数値」として昇順(小さい順)にソートするときには以下のようになります

    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以外で使わないようにしましょう


配列の関数 sort

「数値」として降順(大きい順)にソートする場合、以下の2つの書き方ができます。

    my @num = ( 5, 200, 40, 3, 1 );
    my @sorted1 = sort { $b <=> $a } @num;
    print "@sorted1\n";    # 200, 40, 5, 3, 1

    my @sorted2 = reverse sort { $a <=> $b } @num;
    print "@sorted2\n";    # 200, 40, 5, 3, 1

ハッシュ


ハッシュとは

ハッシュはPerlのデータ構造の1つで, 連想配列 とも呼ばれます

配列と同じく, 要素の格納・取り出しができます

ただし, 要素は 名前 のペアで格納されます

配列の一つ一つの要素にアクセスする場合は $変数名[添字] を使います

第2回 配列要素の添字

ハッシュは添字ではなく、 名前 でデータにアクセスします

要素を指定するための名前を key と呼び, key によって指定される値を value と呼びます


ハッシュを作ってみよう

    my %hash = (
        name => 'Alice',
        age  => 16,
    );

ハッシュは % を使って定義します

=> はファットコンマ演算子と呼ばれ, コンマと同等の役割を果たします

左にkey(名前), => , 右にvalue(値)と順番に書くことで, 関係性が明確になります

keyは文字列として解釈されるので, クォートの必要はありません

1つのハッシュ内に文字列や数値が混在しても構いません

最後の要素に , があってもなくても構いませんが, 追加や変更の可能性をふまえて付けることをお勧めします.


ハッシュを使ってみよう

ハッシュの要素にアクセスし, 取り出してみましょう

ハッシュにアクセスするときは, 添字の指定は波括弧 { } を使います

{ }にkey(名前)を入れることで、対応するvalue(値)を取り出せます

    my %hash = (
        name => 'Alice',
        age  => 16,
    );
    print "$hash{name}\n";    # Alice
    print "$hash{age}\n";     # 16

ハッシュを使ってみよう

ハッシュに新たな要素を代入してみましょう。 取り出すときと同様に、{key} を使います。

    my %hash = (
        name => 'Alice',
        age  => 16,
    );
    $hash{job} = 'Programmer';    # key 'job', value 'Programmer'を追加
    print "$hash{job}\n";         # Programmer

これで、ハッシュの中身は以下のようになりました。

        name => 'Alice',
        age  => 16,
        job  => 'Programmer',

既に存在する key の値を代入すると, 上書きされます


ハッシュの基本

ハッシュには他にも利点があります。

以下のような配列があったとき、

    my @user = ( 'Name', 'Job', 'Affiliation' );
    print "$user[1]\n"    # Job

もし突然、要素の順番が入れ替わってしまったらどうなるでしょう?

    my @user = ( 'Affiliation', 'Name', 'Job' );
    print "$user[1]\n"    # Name

同じ添字 [1] でも、添字と値の関係が変わってしまうため、影響するコードを書き換える必要がでてきます


ハッシュの基本

しかしハッシュであれば, 値は添字の数値(順番)ではなく, 名前(key)で対応づけられているので, 順番の変更に影響を受けません。

    my %user = (
        affiliation => 'PerlEntrance',
        job         => 'Programmer',
        name        => 'Alice',
    );

    print "$user{name}\n";       # nameが表示される => "Alice"
    print "$user{job}\n";        # jobが表示される => "Programmer"
    print "$user{affiliation}\n";# affiliationが表示される => "PerlEntrance"

ハッシュの中身を見たい!

    my %hash = (
        name => 'Alice',
        age  => 16,
        job  => 'Programmer',
    );

    print "%hash\n";   # %hash 変数名がそのまま表示される
  • 質問: ハッシュの中身を全部一度に見たい場合はどうするの?変数展開できない!

  • 回答: Data::Dumper モジュールを使います。これについては第4回で解説します。


練習問題

次の処理をする hash_profile.pl を作りましょう。

  1. 自分の名前 (name), 年齢 (age), 好きな食べ物 (food) を key にしたハッシュ %my_profile を作ってください

  2. key である name, age, food を使って、それぞれの value を出力してください


ハッシュの操作


ハッシュの操作 keys, delete, exists

ハッシュを便利に扱うための関数について説明します。

  • keys

  • delete

  • exists


keys

    my %hash = (
        name        => 'Alice',
        job         => 'Programmer',
        affiliation => 'PerlEntrance',
    );
    my @keys = keys %hash;
    print "@keys\n";    # name job affiliation (順不同)

keys 関数は、ハッシュの key を配列にして返します

ただし、この時 key は 順不同 で返ってきます. ハッシュに書かれた順番で返ってくるとは限りません

同じ順番で受け取りたい場合は, sort 関数を使って並び替えましょう

値のみをを順不同で受け取る values 関数もありますが, ここでは説明しません


delete

    my %hash = (
        name        => 'Alice',
        job         => 'Programmer',
        affiliation => 'PerlEntrance',
    );
    delete $hash{affiliation};

    print "$hash{affiliation}\n"    # 「おまじない」記載時エラーになる

delete 関数は、指定したハッシュの key と、それに対応する value を削除します


exists

    my %hash = (
        name        => 'Alice',
        job         => 'Programmer',
        affiliation => 'PerlEntrance',
    );
    if ( exists $hash{job} )  { print "exists\n" }    # exists
    if ( exists $hash{team} ) { print "exists\n" }    # 何も出てこない

exists 関数は, 指定したハッシュの key が存在するか確認します

存在すれば 1 を返し, 存在しなければ ' '(空文字)を返します


ハッシュの key 指定について

    my %hash = (
        name        => 'Alice',
        job         => 'Programmer',
        affiliation => 'PerlEntrance',
    );
    my $key = 'job';
    print $hash{$key};    # Programmer

ハッシュの key は文字列が入ったスカラー変数でも指定可能です。

  • {foo} であれば foo という文字列が key 名

  • {$foo} であればスカラー変数 $foo に代入された文字列が key 名となります。


ハッシュの key 指定について

    my %hash = (
        name        => 'Alice',
        job         => 'Programmer',
        affiliation => 'PerlEntrance',
    );

    for my $key ( keys %hash ) {
        my $value = $hash{$key};
        print "$key => $value\n";
    }

keys 関数と組み合わせると、keyとvalueのペアをfor文で一つずつ処理することができます。


練習問題

次の処理をする hash_func.pl を作りましょう。

  1. keys 関数を使って, hash_profile.pl で作ったハッシュのkeyをすべて出力してください

  2. delete 関数を使って, 1で使ったハッシュから年齢( age )の要素を削除してください

  3. exists 関数を使って、name, age, food の各要素が存在するか確認してください. 存在している場合は name is exist., 存在しない場合は name is not exist. と表示してください


復習問題

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

練習問題の解答例

  • 2019-answer

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

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

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

落ち穂拾い while ループ

    my @array = ( 1, "foo", 3 );
    my $i = 0;
    while ( $i < scalar(@array) ) {
        print "$array[$i]\n";
        $i++;
    }

while ループを使って, for ループと同じように繰り返し処理ができます

whileの()の中には, 繰り返しを行うための条件式を書きます

条件式が「真」である限り、whileループは動き続けます


while ループ

  • forループでもwhileループでも同じ処理は書けますが, それぞれ適している・好まれるケースがあります

    • forループは配列全てに対して処理を行う時など, 繰り返す回数が決まっている場合に好まれる書き方です

    • whileループは繰り返す回数は決まっていないが, 特定の条件が真の間ずっと処理を繰り返したいときに好まれる書き方です

  • whileループの条件式を間違えると, 応答がなくなる「無限ループ」という状態に陥ります. その時は Ctrl(Control)キーを押しながらCを押すことで強制的に止めることが可能です


お疲れ様でした!

  • 長い時間, Perl入学式第2回お疲れ様でした!

  • 是非Perl入学式のslackに参加して, サポーターや参加者の皆さんと交流しましょう.

  • 不明点もslackで是非質問してください.

  • 第3回以降の参加もお待ちしております!


次回予告

  • サブルーチン

  • 正規表現

  • 第1回〜第2回までのまとめ

  • リファレンスがないとできないこと

You can’t perform that action at this time.