Perl入学式#6の補講に参加

今月もPerl入学式 プログラミング初心者のためのPerl入門講座の第6回目に参加した。と思いきや当日体調不良のため欠席。その代わりに補講に出てきた。

参加者3名に対して講師2名という贅沢な構成。意外と補講の方がお勧めかもしれん。

だんだん新しい概念の話題はなくなってきて、これまでの復習になってきた。本講であまり先に進めなかった事情もあったのかもね。


1.関数の復習
名前と身長と体重をコンソールから入力して、BMI値と共に結果をコンソールに表示する。

my %person;

print "名前: ";
chomp($person{name} = <STDIN>);

print "身長(cm): ";
chomp($person{height} = <STDIN>);

print "体重(kg): ";
chomp($person{weight} = <STDIN>);

sub calc_bmi {
    my ($weight, $height) = @_;
    return $weight / ( ($height / 100.0) **2 );
}

my $bmi = &calc_bmi($person{weight}, $person{height});

printf("%sさんのBMI値は%.2fでした\n", $person{name}, $bmi);

今回はこれをハッシュのリファレンスを渡すことで、せっかく作った %person を生かしたい、という課題。書き換えるとこんな風

sub calc_bmi {
    my ($person) = @_;
    return $person->{weight} / ( ($person->{height} / 100.0) **2 );
}

my $bmi = &calc_bmi(\%person);

誰しも思うところは、こう書き換えてしまうと calc_bmi が引数としてどんなものを要求しているのかわかり難くなる。これは Perl に限らず Ruby でも似たような事情にあると思う。
講義ではバリデータのようなモジュールを利用することもある、程度でさらっと流れる。ググってみると色々ある。試しに Smart::Args とかで書くと

use Smart::Args;

sub calc_bmi {
    args my $name   => { optional => 1},
         my $height => 'Int',
         my $weight => 'Int';
    return $weight / ( ($height / 100.0) **2 );
}

my $bmi = &calc_bmi(%person);

多分、こんな感じ。

今回やったのは、おおまかに言うとこれ位。あとは後置 if とか unless とか、ループで脱出する時に last とか。

2.質問タイム

前回疑問のまま放置していた、utf-8エンコードされた日本語ファイルの入出力の件について質問しておいた。非常に適当に要約すると、ファイルを読込む時や書き込む時に必要とするエンコーディング

open my $fh, "<:encoding(UTF-8)", "file1.txt" or die;

とか

open my $fh, ">:utf8", "file2.txt" or die;

のように指定してやると、Perlの内部エンコードとファイルの持っている外部エンコーディングを相互に変換してくれるようだ。

Encode::encode_utf8($line);

のように一々変換してもいいようだが、面倒なだけだな。ただ qx{} で戻ってくるコマンドの結果はやはり外部エンコーディングUTF-8 なのでそれを Perlスクリプト内で利用しようとすると

my $result = Encode::decode_utf8(`some_command`);

のように内部エンコーディングにデコードする必要があるようですな。