「初めてのPerl」 6章 (入出力の基本)

mixiの1979(昭和54)年会のトピックで知ったのですが、「俺たち、サザエさんのアナゴさんとタメだ。」そうです。素でショックです…。という話はさておき、少し間が空きましたが、まだちゃんとPerlを勉強しているbonlifeです。6章では入出力の基本について扱っています。演算子を使って標準入力を読み込む方法や<>(ダイヤモンド演算子!)を使って起動引数を読み込む方法が紹介されています。後半部分ではprintfを使ったフォーマット付き出力(出力の整形)についても簡単に触れられています。ということで、6章の演習問題のnot模範解答です。
ex6-1.pl

  • catのような振舞いをするプログラムを書く
  • 出力を逆順に行う (複数の引数を指定した場合、最後の引数の最後の行から表示)
#! perl -w
use strict;
print reverse <>;

出力結果は以下の通り。

ex6-1.pl test01.txt test02.txt test03.txt
line 5 of test03.txt
line 4 of test03.txt
line 3 of test03.txt
line 2 of test03.txt
line 1 of test03.txt
line 5 of test02.txt
line 4 of test02.txt
line 3 of test02.txt
line 2 of test02.txt
line 1 of test02.txt
line 5 of test01.txt
line 4 of test01.txt
line 3 of test01.txt
line 2 of test01.txt
line 1 of test01.txt

正解を見て気づいたことは特になし。同じ。
ex6-2.pl

  • 文字列のリストを1行に1個ずつ読み込んで、20文字幅のカラムに右寄せ表示
  • 出力を確認するために目盛りも出力
#! perl -w
use strict;
my ($count, @words, $word);
print "Please input some words : \n";
chomp(@words = <STDIN>);
$count = 0;
while ($count < 6 ) {
	foreach (1..10) {
		if ( $_ != 10 ) {
			print $_ ;
		} else {
			print 0;
		}
	}
	$count += 1;
}
print "\n";
foreach $word (@words) {
	printf "%20s\n", $word ;
}

出力結果は以下の通り。(^Zまでは入力)

ex6-2.pl
Please input some words :
hello
good-bye
^Z
123456789012345678901234567890123456789012345678901234567890
               hello
            good-bye

正解を見て気付いたことは以下の通り。

  • 目盛りの出力方法が冗長 (解答例では x を使って1234567890を繰り返し)
    ベタに1234...と記述するのを避けようと思ったのが裏目に出てしまいました
  • foreachでの出力では、変数名を宣言せず、デフォルトの $_ を使う

ex6-3.pl

  • 2のプログラムを改造して、ユーザがカラム幅を指定できるようにする
    例えば30とhelloとgood-byeを入力すると、30文字幅のカラムに右寄せで表示
  • 長い幅を指定された場合は、それに合わせて目盛りも伸ばす
#! perl -w
use strict;
my ($count, @words, $word, $col, $ruler_size);
print "Firstly, please input column number.\nAfter that, pls input some words : \n";
chomp(@words = <STDIN>);
$col = shift(@words);
$ruler_size = $col / 10;
if ( $ruler_size < 6 ) {
	$ruler_size = 6;
} 
$count = 0;
while ( $count < $ruler_size ) {
	foreach (1..10) {
		if ( $_ != 10 ) {
			print $_ ;
		} else {
			print 0;
		}
	}
	$count += 1;
}
print "\n";
foreach $word (@words) {
	printf "%${col}s\n", $word ;
}

出力結果は以下の通り。(^Zまでは入力)

ex6-3.pl
Firstly, please input column number.
After that, pls input some words :
18
hello
good-bye
^Z
123456789012345678901234567890123456789012345678901234567890
             hello
          good-bye
ex6-3.pl
Firstly, please input column number.
After that, pls input some words :
75
hello
good-bye
^Z
12345678901234567890123456789012345678901234567890123456789012345678901234567890
                                                                      hello
                                                                   good-bye

正解を見て気付いたことは以下の通り。

  • カラムの指定と単語の入力は分けて行わせた方が分かりやすい
  • 解答例では、目盛りの伸ばし方が絶妙
    "1234567890"を(指定文字幅+9)/10回(切捨て)繰り返す

3問目で数学的な発想が欠如していることを思い知らされました。むむぅ。まぁ、とりあえず動くソースが書けたのでオーケーということにしておきます。ダイヤモンド演算子を上手いこと使えば現在シェルでやってるようなことがだいぶ出来る気がします。後は11章のファイルハンドルについてもきっちり学んでおく必要がありそうですね。引き続き細々とPerlを勉強していきます!

「初めてのPerl」 5章 (ハッシュ)

連想配列という言葉が長いからって「ハッシュ」と呼んでしまうPerl。この短さへの美学に少しでも迫れたら良いな、と思いながら勉強しているbonlifeです。ハッシュは名前をつけた箱にキーと値の組み合わせ放り込んで管理するイメージ。なんかちょっと違う気もしますが、まぁそんな感じです。ハッシュ全体を扱う時はパーセント記号(%)を使い、1つ1つの要素にアクセスする場合には、$hash{$some_key}となります。この頭の記号がコロコロ変わるのに慣れないといけませんね。
演習問題を解いてみました。だんだん書くのに時間がかかるようになってきました。先行き不安です…。

#! perl -w
use strict;
my %last_names = ( "fred" => "flintstone", "barney" => "rubble", "wilma" => "flintstone" );
print "Please input first name : ";
my $first_name = <STDIN>;
chomp $first_name;
my $last_name = $last_names{$first_name};
if ( ! $last_name ) {
	print "No last name found for $first_name.\n";
} else {
	print "The last name of $first_name is $last_names{$first_name}.\n";
}

出力結果は以下の通り。

ex5-1.pl
Please input first name : fred
The last name of fred is flintstone.
ex5-1.pl
Please input first name : bonlife
No last name found for bonlife.

正解を見て気付いたことは以下の通り。

  • 標準入力を変数に格納した後、chompする処理は1行で書ける
  • ハッシュに値を入れる方法は色々ある (qw//リストなど)

ex5-2.pl

  • 単語をいくつか入力させ、各単語が何回出現したかを表示
  • 単語をASCIIコードの昇順にソートして表示
#! perl -w
use strict;
print "単語を次々と入力してください。カウントします。 : \n";
my @names = <STDIN>;
chomp @names;
my %result;
foreach (@names) {
	$result{$_} += 1;
}
my @keys = sort keys %result;
foreach (@keys) {
	print "$_$result{$_} 個ありました。\n";
}

出力結果は以下の通り。

ex5-2.pl
単語を次々と入力してください。カウントします。 :
fred
barney
fred
dino
wilma
fred
^Z
barney は 1 個ありました。
dino は 1 個ありました。
fred は 3 個ありました。
wilma は 1 個ありました。

正解を見て気付いたことは以下の通り。

  • 変数の宣言はまとめて行える (あちこちで宣言すると分かりづらい)

ダイアログを英語で書いたり、日本語で書いたり統一感がなくなってきちゃいましたよ。今後は英語で頑張ってみます。

「初めてのPerl」 4章 (サブルーチン)

そこそこ良いペースで勉強が進んでいる気がしているbonlifeです。この章で学んだのはsubで定義して&で呼び出すサブルーチンです。最後に評価された式の結果が自動的に戻り値になる、ってのに少し違和感があります。ここは注意しなきゃ。後、引数の渡し方も結構ルースですよね。なんでもかかってこい状態で、やってきたものを適宜処理する感じです。「不必要な制限を導入しない」哲学、恐るべし。レキシカル変数はしっかり使いこなさないとマズイですね。
では、演習問題です。今後はこの章で紹介されていたuse strictプラグマを使っていきます。
ex4-1.pl

  • 数値のリストを受け取って、その合計を返すサブルーチン&totalを書く
#! perl -w
use strict;
my @fred = qw { 1 3 5 7 9 };
my $fred_total = &total(@fred);
print "The total of \@fred is $fred_total.\n";
print "Enter some numbers on separate lines : ";
my $user_total = &total(<STDIN>);
print "The total of those numbers is $user_total.\n";
sub total {
	my $sum;
	foreach (@_) {
		$sum += $_;
	}
	$sum;
}

出力結果は以下の通り。

ex4-1.pl
The total of @fred is 25.
Enter some numbers on separate lines : 1
2
3
4
5
^Z
The total of those numbers is 15.

正解を見て気付いたことは特になし。
ex4-2.pl

  • 前の問題で作成したサブルーチンを使用して、1から1000までの合計を求めるプログラムを書く
#! perl -w
use strict;
my @number_list = 1..1000;
print &total(@number_list) . "\n";
sub total {
	my $sum;
	foreach (@_) {
		$sum += $_;
	}
	$sum;
}

出力結果は以下の通り。

ex4-2.pl
500500

正解を見て気付いたことは以下の通り。

  • 出力をもう少し分かりやすくする
  • 一時的にリストを配列に保存する必要はない (直接&totalにリストを渡すべき)

やはり分かりやすさに対する配慮が足りていないですね。気をつけなきゃ。後、必要以上に何でも箱(変数や配列)に入れたくなってしまう癖はPerlっ子っぽくないので直していこうと思います。おいおい、そりゃないぜ、的な記述を見つけた方はコメントにて教えてくださいませ。

「初めてのPerl」 3章 (リストと配列)

いつかはPlaggerを使いこな…bonlifeです。昨夜、今朝の電車で4章の途中まで読めました。とりあえず3章はリストって概念がなんだか分かりづらいです。(まぁ、リストなんですけどね。)qwショートカットもなんだか見慣れない感じですし。スカラーコンテキストとリストコンテキストについてはおよそ理解し(たつもりになり)ました。これはPerlを使っていくうちに慣れてくるんでしょうね。そんなこんなで、3章の演習問題を解いてみました。

ex3-1.pl

  • 何個か文字列を入力させ、その内容を逆順で表示する
#! perl -w
chomp(@lines = <STDIN>);
@lines = reverse @lines;
foreach $line (@lines) {
	print "$line\n";
}

出力結果は以下の通り。(^Zまでは入力)

ex3-1.pl
a
b
c
d
^Z
d
c
b
a

正解を見て気付いたことは以下の通り。

  • 入力を促すメッセージをprintしてあげた方が良い
  • 配列の値を逆順にしたものは別の配列に代入してあげた方が良さそう
  • chompなどしないで短く書くのがPerlの美学らしい

ex3-2.pl

  • 人名リストをプログラム中にハードコード
  • 数値を入力させ、その番号に対応する名前を出力
#! perl -w
@names = qw / fred betty barney dino wilma pebbles bamm-bamm /;
chomp(@numbers = <STDIN>);
foreach $number (@numbers) {
	print "$names[$number - 1]\n";
}

出力結果は以下の通り。(^Zまでは入力)

ex3-2.pl
1
2
4
2
^Z
fred
betty
dino
betty

正解を見て気付いたことは特になし。ほぼ同じ。
ex3-3.pl

  • 何個か文字列を入力させ、その内容をASCIIコード順に表示
  • すべての文字列の1行表示と文字列ごとに行を分ける表示を実現する
#! perl -w
chomp(@words = <STDIN>);
@words = sort @words;
if ( $ARGV[0] eq "-l" ) {
	$separator = "\n";
} else {
	$separator = " ";
}
foreach $word (@words) {
	print "$word$separator";
}

出力結果は以下の通り。(^Zまでは入力)

ex3-3.pl
fred
barney
wilma
betty
^Z
Use of uninitialized value in string eq at C:\test\perl\ex3-3.pl line 4, <STDIN> line 4.
barney betty fred wilma
ex3-3.pl -l
fred
barney
wilma
betty
^Z
barney
betty
fred
wilma

正解を見て気付いたことは以下の通り。

  • やっぱりchompせずに改行ごと出力するんですね
  • 引数で分けずに2つのパターンを考えれば良かったようです

こんな感じで続けてみます。O'reilly的正解を確認したい方はお近くの書店などで「初めてのPerl」をチェキってみてくださいませ。

Perlの勉強始めました

昨夜、通称リャマ本こと「初めてのPerl」が届きましたよ、bonlife。(この本がラクダ本だと思ってたのですが、あの激しく重そうな通勤勉強には向かない方がラクダ本だったんですね…。)はてブ人気エントリーをボンヤリと眺めていたら以下のような記事がありました。

私が思うに、RubyPerlの守備範囲を何なくカバーしてしまっているので、 Rubyが使えるとPerlは要らないんですよね。すでにPerlで書かれているプログラムを別にすれば。

ガビョーン。いきなりもうPerl駄目だなんて!せっかく今朝から勉強始めたのになぁ。さっそくRubyに…という気分になりましたが、そもそも会社のAIXではRubyが使えないのでPerlを勉強し始めたんですよ。ということで「Rubyが使えると」という条件を満たしていないのでセーフ。と思い込むことにしました。まぁ、本格的にPerlで何かしようと考えてるわけじゃないですし。(というより、何かを本格的にやるほどのアイディアもスキルもないのですが…。)
ちなみに、本日は2章まで読み終わりました。(ちゃんと演習問題もやりましたよ!)Perlってboolean型(bool型)がないんですね。未定義値のundefってなんだかちょっと怖い感じです。なんとなく書いたコードがなんとなく動いちゃいそう。(それはそれで楽で良いのかな。)chompもなんだか慣れない感じです。元のスカラー変数の末尾の改行を削除した値を返すわけじゃなくて、スカラー変数の改行を削除してしまうんですね。ふーん。とまぁ、こんな感じで思いついたことをメモしていこうと思います。
リャマ本だけなら当初の目標期間の2ヶ月は要らなそうですね。通勤時間だけでも1ヶ月弱でなんとかなりそうな予感。(とか言いつつ、2ヶ月かかったりするかもしれません。)

続きを読む

「初めてのPerl」を注文しました

手作業だと2時間かかる処理を2時間半かけてシェルを書いて処理したりしているbonlifeです。少しだけPerlの勉強をしてみようと思い、オススメの書籍を人力検索はてなで質問して聞いてみました。その結果、やはりO'reillyの「初めてのPerl」が定番のようでしたので、とりあえずAmazonで注文してみました。

初めてのPerl

初めてのPerl

図書館にあったら一度借りてみようと思ったのですが、初版、第2版しか置いてなかったのです。仕方がないので買っちゃいました。cygwinbashAIXcshって感じで使い分けてると文法の違いで混乱するので、多少速度に難があるとしても、今後はPerlで細々したスクリプトを書こうと思います。
それはそうと、Amazonから図書館蔵書検索のGreasemonkeyは有名ですよね。あれのSeaHorse版を誰か作ってくれないかしら。大阪市立図書館の状況をAmazonのページで確認したいのですが、自力ではちょっと難しいです。東京のやつだとTABLEタグの有無で判定してますが、大阪市立図書館の場合はFRAMESETで判定できそうなので、通信部分を上手いこと書き換えられればすぐ動きそうなんですけどね。(XMLHTTPRequestの代わりにActiveXObjectを使うんですよね、確か。あれ、違うかな。)他力本願ですが、どなたかよろしくお願いいします!