15 5月

perl入学式#4補講に参加してきました

毎月参加してるperl入学式
4月15日に開催された#4は仕事の都合で行けなかったので結構無理を言って有給もらって参加しました。
有給取れるよう調整してくださった関係者各位に感謝。

というわけでまずは#3までのおさらいから始まり。
その前に今回の資料はこれ
http://nqounet.github.com/presentation/20120415_perlentrance4

前回までのおさらい

まずは基本のおまじない。

[perl]

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

[/perl]

もうここまでの記述はテンプレートつくっておくのが一番ですね。
そのあとはprint文、変数、配列、条件分岐、比較演算子、繰り返しなどなど
前回までに解説のあったことのおさらいです。 おさらいの最後に練習問題をやりました。

おさらい問題

標準入力(STDIN)から値を5つ受け取って「受け取った値の全て」と
「数値としての最大値」を表示するプログラムを作ってみよう

回答方法

  1. for文と配列を使って書いて実行してみよう
  2. (余裕があれば)「数値としての最小値」も表示してみよう
  3. (余裕があれば)数値として0が入力された場合にエラーを出すようにしよう

まず最初につくった回答がこれ

[perl]

#!/usr/bin/env perl

use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

my @input;
print "0以上の整数を5つ入力してくださいn";
for my $i (1 .. 5) {
chomp(my $input = <STDIN>);
if ($input != 0) {
push (@input,$input);
}
else{
print "エラーですn";
}
}

print "入力された値は@{input}です。n";
my @input2 =sort{$a <=> $b}@input;
print "最大値は${input2[-1]}です。n";
print "最小値は${input2[0]}です。n";

[/perl]

がここで問題がsort関数使って配列内を並び替えてから最大値を最小値を取りだした のですが
これは禁じ手だったというわな。 次回以降で解説される予定だったそうな。 というわけでやり直し。

それでつくりなおしたのがこれ

[perl]
#!/usr/bin/env perl

use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

my @input;
my $max;
my $min;
my $tmp;

print "0以上の整数を5つ入力してくださいn";
for my $i (1 .. 5) {
chomp(my $input = <STDIN>);
if ($input != 0) {
push (@input,$input);
}
else{
print "エラーですn";
}
}

print "入力された値は@{input}です。n";
$max = $input[0];
$min = $input[4];
for my $i (0 .. 4){
$tmp = $input[$i];
if ($tmp <= $max){
$max = $tmp;
}
if($tmp >= $min){
$min = $tmp;
}
}

print "最大値は${max}です。n";
print "最小値は${min}です。n";
[/perl]

最大値と最小値をif文で取り出すようにしました。 これ後で見直すと2回目のfor文の$iか
$tmpかのどっちかいりませんね。
まあこれでも動きました。 がこれだと0が入力された際配列に何も格納されないまま 処理
されてしまうので ちょっと問題ありです。

そこで修正したのが以下の通りです。

[perl]
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

my @input;
my $max;my $min;
my $tmp;

print "0以上の整数を5つ入力してくださいn";
while (@input < 5){
chomp(my $input = <STDIN>);
if ($input != 0) {
push (@input,$input);
}
else{
print "エラーですn";
}
}

print "入力された値は@{input}です。n";
$max = $input[0];
$min = $input[4];
for my $i (0 .. 4){
$tmp = $input[$i];
if ($tmp <= $max){
$max = $tmp;
}
if($tmp >= $min){
$min = $tmp;
}
}

print "最大値は${max}です。n";
print "最小値は${min}です。n";
[/perl]

何が変わったのかというと最初の標準入力のところがforループからwhileループに なったこと
0が入力された場合はエラーですとだけ表示されて変数に値が格納されないため5個0以外
の数位が格納されるまでループが回り続けます。 これで問題は解消。 問題にfor文と配列を
使ってって書かれたのが微妙に罠な感じがするけどまあ気にしない。 あとはモジュールの紹
介として最大値を最小値をさくっと取り出せるモジュールの 紹介がありました。 実際に使って
描くとこれが

[perl]
$max = $input[0];
$min = $input[4];
for my $i (0 .. 4){
$tmp = $input[$i];
if ($tmp <= $max){
$max = $tmp;
}
if($tmp >= $min){
$min = $tmp;
}
}
[/perl]

[perl]
my $max = max(@input);
my $min = min(@input);
[/perl]

こうなります。 2行になってしまいました。 モジュールってすばらしい。 ここでいったん休憩。

cpamモジュールの紹介

次にcpamモジュールの紹介がありました。
ここは資料を見てもらうのが早いしわかりやすいかなと。
というわけでカット。 他にも正規表現のざっくりとした解説などなどありました。
このあたりも詳細は資料を見てください。

ハッシュを使おう

ハッシュとは配列の一種。インデックスの代わりに文字列をキーとして値を参照する。
連想配列ともいう。定義するときは「%hash」的な感じで頭に%をつけるとハッシュと して定義される。
値を取り出すときは「{}ブレース(中括弧)」を使う。 ハッシュも配列と同様に以下のように定義できる。

[perl]
my %hash1 = (‘one’, ‘two’, ‘three’, ‘four’);
my %hash2 = (‘1’, ‘2’, ‘3’, ‘4’);
[/perl]

しかしこの場合だと奇数番にある値はキーとして処理され偶数番にある値はキーに紐付く値として処理される。

たとえば

[perl]
print "$hash1{one}n";
[/perl]

とした場合は「two」と表示される。 また配列と異なる点として

[perl]
print %hash1;
[/perl]

とした場合は格納されている値がランダムに表示される。

他にも

[perl]
print "%hash1n";
[/perl]

とした場合は格納されている値は表示されず「%hash1」と表示される。
ハッシュを定義するときは以下のように書くとわかりやすくあとあとのメンテナンスも楽になる

[perl]
my %hash  = (
‘key1’ => ‘value1’,
key2   => ‘value2’,
);
[/perl]

「=>」はファットカンマと呼ばれカンマとほぼ同じ意味を持つ。
またハッシュの最後の値の後のカンマは必須ではないが後日値を追加することや順番を入れ
替えるときに カンマをつけ忘れて正常に実行されないといったことを避けるためにつけておくほうがベター。
ハッシュの便利なところは値に対してキーで名前付けできるので取り出したい値を覚えやすくまたその値が
どういう値なのかソースをみて理解しやすいということらしいです。 このあたりは実際に使いこんでみるとわかるのかな。

ハッシュの中身を確認する方法としてはeachという関数を使う。 この関数はハッシュのキーと値をペアで返す関数。
資料にある以下のソースコードを実際に実行するとこうなる。

[perl]
my %nqounet = (
twitter => ‘nqounet’,
age     => ’38’,
lang    => ‘Perl’,
);
while ( my ($key, $value) = each %nqounet ) {
print "$key : $valuen";
}
[/perl]

実行結果
===============================================
lang : Perl
twitter : nqounet
age : 38
===============================================

データの中身を簡単に確認する方法

配列やハッシュはデータの中身をみるのが面倒。
特にハッシュはprint文1行では簡単に見れないからめんどくさい。
それを簡単に見るために使うのが「Data::Dumper::Concise」というモジュールを使う。
資料の以下のサンプルプログラムを実際に実行するとこんな感じに表示される

[perl]
#!/usr/bin/env perl

use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力
use Data::Dumper::Concise; # Dumperという関数を生成

my %nqounet = (
twitter => ‘nqounet’,
age     => ’38’,
lang    => ‘Perl’,
);

print Dumper( %nqounet );
[/perl]

実行結果
=====================================================
{
age => 38,
lang => “Perl”,
twitter => “nqounet”
}
=====================================================

1行で表示されました。
楽ちん!

たくさんの情報を持ちたい

多くの情報を持ったハッシュを作りたいときにハッシュの中に配列を代入すると残念なことになる。
詳細は資料で!

でどうするかというとリファレンスを用いて階層構造を作る。
サンプルプログラムは資料の通りなので割愛

ざっくり自分の中でリファレンスをまとめると変数や配列、ハッシュの1つ以上のスカラー値を持ったものを
tarで固めてそれを変数や配列に格納する感じという認識になった。
厳密に言うと違う気もするけど今回のところはそんな感じの認識。

宿題のリファレンスを使った練習問題

Dumperすると、以下のようになるような変数を作成してください

====================================================
{
  luigi => {
    color => "green",
    initial => "L"
  },
  mario => {
    color => "red",
    initial => "M"
  }
}
====================================================

んで自分がつくったプログラムがこれ

[perl]
#!/usr/bin/env perl

use utf8;
use strict;
use warnings;

binmode STDIN,  ":utf8"; # 標準入力
binmode STDOUT, ":utf8"; # 標準出力
binmode STDERR, ":utf8"; # 標準エラー出力

use Data::Dumper::Concise; # Dumperという関数を生成

#use Data::Dumper::Concise;
my %luigi = (
color => "green",
initial => "L",
);
my %mario = (
color => "red",
initial => "M"
);
my %brothers = (
luigi => %luigi,
mario => %mario,
);
print Dumper %brothers;
[/perl]

なんか最後がかなりはしょった感あるけど今回のまとめはこんな感じです。
次回の#5はまた仕事の都合で参加できないんですが#5の補講はたぶん行けるかな。

最後になりましたが今回の講師をしてくださった若林さんありがとうございました。