Perl はじめました(冷やし中華風に)。
今まで、いろいろ言語やツールの使い方を覚えましたが、いつも学習過程の記録を残しておかなかったため、後からまとめを書こうと思い立っても、新鮮味がなく、つまらないものになるのが見えてしまうので諦めてきました。今回は、学習途中に気づいた点をその場で随時記録していこうと思います。
参考書としてまずは「とほほのperl入門」をメインにします。
処理系は Active State の Windows 用の Active Perl をダウンロードしてインストールしました。拡張子 .msi ってなんだと思っていたら、どうやらインストーラのそのまたインストーラをインストールしたら使えるようになるものらしいです。
インストールはできたものの、HTML 中で VBScript や JavaScript と同様に PerlScript が使えるらしいのですが、なぜか動かない。とりあえずは、地道に C:\Perl\bin\perl.exe を呼び出すことで起動することにします。
perl hogehoge.pl
で動くので手軽です。とりあえず、変数(や配列・連想配列)の扱いを重点に調べていくことにします。
$x = 123; print "x = $x";結果は
@a = (123, 456, 789); $a[1] = 654; print "0th = $a[0], 1st = $a[1], 2nd = $a[2]\n";結果は
@a = (123, 456, 789); $a[1] = 654; print "0th = @a[0], 1st = @a[1], 2nd = @a[2]\n";これも結果は
@a = (123, 456, 789);
$i = 0;
foreach $p (@a) {
print "$i th = $p\n";
$i++;
}
結果は
0 th = 123 1 th = 456 2 th = 789となり、もくろみどおりでした。
@a = (123, 456, 789);
for ($i = 0; $i < 3; $i++) {
print "$i th = $a[$i]\n";
}
とやっても同じ結果を得ることができました。
なお、当初、foreach のループの中で、
print "$ith = $p\n";
と書いたところ、結果は
= 123 = 456 = 789となり変数名として $ith というものとして評価されるらしく、常に長さ0の文字列とみなされるようでした。字を詰めて書きたいときはどうすればよいのでしょうか。
また、似た話として for のループの中で
print "$i th = $a[i]\n";
と書いたところ、結果は
0 th = 123 1 th = 123 2 th = 123これもやはり $a[0] として評価されるようでした。未定義のものがあれば警告するようにはできるのでしょうか。
@a = (123, 456, 789);
for ($i = 0; $i <= $#a; $i++) {
print "$i th = $a[$i]\n";
}
要素数ではなく、要素の最大値なので 1 だけ小さい値になり、ちょっと扱いにくいですね。
ちなみにこれは @#a だと syntax error になりました。
なお、要素数が 0 の場合は最大値は -1 になるのかと思い、
@a = (); print "$#a\n"; @b = (123); print "$#b\n";とやってみたところ、結果は予想通り、
-1 0になました。このあたりは VB と同じですね。
なお、今まであまり気にしていませんでしたが、要素番号は 1 からではなく 0 から数えるようです。
単なる配列は @ を付けましたが、連想配列は % を付けるそうです。
こんな感じかと思って試してみました。
%h = {};
$h{"abc"} = "book";
$h{"xyz"} = "desk";
$i = 0;
foreach $p (%h) {
print "$i th = $p\n";
$i++;
}
すると結果は、
0 th = HASH(0x176f150) 1 th = 2 th = abc 3 th = book 4 th = xyz 5 th = deskのようになりました。どうも低レベルの情報を覗いているような感じです。
次のようにすると良いようです。
$hash{"abc"} = "book";
$hash{"xyz"} = "desk";
$i = 0;
while (($key, $value) = each(%hash)) {
print "$key: $value\n";
}
この結果は次のようになります。
abc: book xyz: desk
$hash{"abc"} = "book";
$hash{"xyz"} = "desk";
@mykeys = keys(%hash);
foreach $p (@mykeys) {
print "key: $p\n";
}
@myvalues = values(%hash);
foreach $p (@myvalues) {
print "value: $p\n";
}
とすると結果は
key: abc key: xyz value: book value: deskと、なりました。
@a = (123, 456, 789); print @a[2]; print "\n"; print $a[2]; print "\n";の結果は
789 789となるように @ でも $ でもどっちでもよいのは、結局はかぎ括弧があるので配列だということが分かってしまうので、あとはパースのための目印は $ でも @ でもどっちでも良くなってしまうということが理由なのだと思います。
@a = (555, 666, 777); $a = (123, 456, 789); print @a[1]; print "\n"; print $a[1]; print "\n"; print $a;とすると結果は、
666 666 789となりました。変数のスコープとしては、配列の @a とスカラの $a は分離しているようです。
また $a が 789 になるということは、配列からスカラへ代入すると、最後の要素が優先されるということでしょうか。
open IN, "hogehoge.txt";
while ($x = <IN>) {
print $x;
}
close IN;
で、指定されたファイル(ここではカレントフォルダの hogehoge.txt)を読んで、そのまま標準コンソール出力に出力します。これはうまく動きました。
しかし、ここで分からないのは、
open(f, "hogehoge.txt");
while ($x = <f>) {
print $x;
}
close(f);
のようにしても動きました。ちなみに open や close は、関数という扱いのものらしく、引数は丸括弧で囲んでも囲まなくてもどちらでもよいようです。
次に
open(f, "hogehoge.txt");
while ($x = f) {
print $x;
}
close(f);
を試したところ、延々と f の文字が出力されてしまいました。f が文字列として解釈されているのでしょうか。ダブルクォーテーションなどで囲まなくても文字列扱いになってしまうのでしょうか。
open($f, "hogehoge.txt");
while ($x = <$f>) {
print $x;
}
close($f);
とやっても動きました。$f でも f でもどちらでもよいのでしょうか。
open($f, "hogehoge.txt");
while (x = <$f>) {
print x;
}
close($f);
だと syntax error になってしまいます。
sub mysub {
$a = $_[0];
$b = $_[1];
$c = $a + $b;
return $c;
}
$x = 345;
$y = 789;
$z = mysub($x, $y);
print $z;
結果は、もくろみどおり、
1134になりました。$z = &mysub($x, $y); のように & を付けても付けなくても同じ結果になります。& は何をするものなのでしょうか。
sub mysub {
$a = $_[0];
$b = $_[1];
$c = $a + $b;
print "inner: x=$a, y=$y, a=$a, b=$b, c=$c\n";
$a = 999;
return $c;
}
$x = 345;
$y = 789;
mysub($x, $y);
print "outer: x=$a, y=$y, a=$a, b=$b, c=$c\n";
の結果は、
inner: x=345, y=789, a=345, b=789, c=1134 outer: x=345, y=789, a=999, b=789, c=1134となりました。サブルーチンの外側から $a などが見えることから、これだとまったくスコープがないことになります。また、$x が書き換わらないことから、(ポインタ渡し・参照渡しではなく)いわゆる値渡しになるようです。
sub mysub {
local($a);
$a = $_[0];
$b = $_[1];
$c = $a + $b;
print "inner: x=$x, y=$y, a=$a, b=$b, c=$c\n";
$a = 999;
return $c;
}
$x = 345;
$y = 789;
mysub($x, $y);
print "outer: x=$x, y=$y, a=$a, b=$b, c=$c\n";
とすると結果は、
inner: x=345, y=789, a=345, b=789, c=1134 outer: x=345, y=789, a=, b=789, c=1134となりました。local があれば my は要らないような気もします。
しかし、
sub sub1 {
print "sub1: $x\n";
}
sub sub0 {
local $x = "sub0";
print "sub0: $x\n";
sub1;
}
$x = "global";
sub0;
とすると、結果は、
sub0: sub0 sub1: sub0となります。
sub sub1 {
print "sub1: $x\n";
}
sub sub0 {
my $x = "sub0";
print "sub0: $x\n";
sub1;
}
$x = "global";
sub0;
とすると結果は
sub0: sub0 sub1: globalとなります。