Perl: 2008年6月アーカイブ

use strict;

my @list = ("a", "b", "c");

my $ref = \@list;


# 配列全体を取り出す

print "@{$ref}\n"; # 出力: a b c

print "@$ref\n";   # 出力: a b c


# 配列の要素を取り出す

print "${$ref}[0]\n"; # 出力: a

print "$$ref[0]\n";   # 出力: a

print "$ref->[0]\n";  # 出力: a

省略のルール

  • { なんちゃら } が単純なスカラー変数の場合は、{ }を省略できる。
  • 例: @{ $ref }  ⇒  @$ref
       ${$ref}[0]  ⇒ $$ref[0]
  • ${ なんちゃら }[1] と書ける全てのコードは、なんちゃら->[1] と書ける。
  • 例: ${$ref}[0] ⇒ $ref->[0]

配列のリファレンスをネスト

リファレンスはネストさせることができます。
階層構造を持ったデータを作るときに便利です。

use strict;


my @array1 = (1, 2, 3);

my @array2 = (2, 4, 6);


my @all = (\@array1, \@array2);

my $ref = \@all;


# 値を取り出す

print "${${$ref}[1]}[2]\n";  # 出力: 6

print "$ref->[1]->[2]\n";    # 出力: 6

print "$ref->[1][2]\n";      # 出力: 6


# 配列を取り出す

print "@{${$ref}[1]}\n";  # 出力: 2 4 6

print "@{$ref->[1]}\n";   # 出力: 2 4 6
まず、@array1と@array2のリファレンスを作って@allに格納します。
次に、@allのリファレンスを作って$refに格納しています。

すると、$refは「配列のリファレンスを格納した配列」のリファレンス ということになります。

デリファレンスの省略記法

2つの法則があります。
  • ${なんちゃら}[1] と書ける全てのコードは、なんちゃら->[1] と書ける。
  • 添え字的なもの間に挟まれている矢印、つまり[1]->[2]とか{'foo'}->{'bar'}とかの矢印は省略できる。
${$ref}[1]  =>  $ref->[1]
$ref->[1]->[2]  => $ref->[1][2]
Perl再入門 | アルパカ本に学ぶリファレンス入門5  ネストした配列リファレンス

無名配列を作る

my $ref;

{
  my @array = (2, 4, 6);
  $ref = \@array;
}

print "@$ref";  # 出力: 2 4 6
@arrayはブロックが終わったときに消滅しますが、$refはブロックが終わっても値を保持します。

このとき、$refは、「名前の無い配列」への「リファレンス」を格納しています。
$refが参照している名前の無い配列を「無名配列」といいます。
($ref自体は「無名配列」への「リファレンス」です。)

値を取り出すときは、通常の配列リファレンスと同じようにデリファレンスします。
print $ref->[1];  # 出力 4

print "@$ref";    # 出力 2 4 6

無名配列へのリファレンスを作る

まず、通常の配列へのリファレンスを作る方法。
my @array = ( 2, 4, 6 );

my $ref = \@array;
一時変数(@array)をいちいち作るのはめんどくさいので、
下記のように書くこともできます。
my $ref = [ 2, 4, 6];
これを無名配列へのリファレンスといいます。

内部的には、無名の配列 (2, 4, 6)を作って、その配列へのリァレンスを作っています。
一時変数がなくなり、コードが読みやすくなりました。

値を取り出すときは、通常の配列リファレンスと同じようにデリファレンスします。
print $ref->[1];  # 出力 4

print "@$ref";    # 出力 2 4 6

リファレンスからデータの実体を取り出すことを、デリファレンスするといいます。

まずは配列。

use strict;

my @list = ("a", "b", "c");
my $ref = \@list;

# 配列全体を取り出す
print "$ref\n"; # 出力: ARRAY(0x1829884)
print "@{$ref}\n"; # 出力: a b c
print "@$ref\n"; # 出力: a b c

# 配列の要素を取り出す
print "${$ref}[0]\n"; # 出力: a
print "$$ref[0]\n"; # 出力: a
print "$ref->[0]\n"; # 出力: a


ご欄のように、同じことをするのに書き方が何通りがあります。

リファレンス入門

Perl入門者がつまづきやすいリファレンスについて、続・初めてのPerl 改訂版(通称アルパカ本)を下敷きにしてわかりやすく解説してみます。

リファレンスというのは、ある変数(データ)へのリンクあるいはショートカットのようなものです。


リンクとコンテンツの関係
例えば、今あなたのお気に入り(ブックマーク)にYahoo!Japanが登録されていたとします。
このとき、実際にお気に入りフォルダに入っているものは、Yahoo!JapanのURL(リンク情報)だけであり、Yahoo!JapanのWebサイトのHTMLコンテンツそのものは格納されていません。

つまり、"http://www.yahoo.co.jp/" というURLは、Yahoo!Japanのサイトのトップページを指しますが、トップページのHTMLコンテンツそのものではありません。あくまでHTMLファイルが置かれている場所を示すアドレスにすぎないのです。

実例
さて、
@list = ("a", "b", "c");
という配列があるとします。 
この配列には3つのデータが格納されています。

ここで、\@listのように配列名の前に\を付けると(Windowsの場合は¥記号)、それは配列@listへのリファレンスを表します。

リファレンスはあくまで配列を指し示すものであって、配列そのものではありません。
リファレンスは、$変数に代入することができます。

$reference_to_list = \@list;  # @listのアドレス(住所)を代入
$reference_to_list_2 = $reference_to_list; # これも、@listを指し示す。
$reference3_to_list3 = \@list; # これも@listを指し示す

この3つの$変数はどれも同じひとつの物(配列@list)を指しています。
なので、@listをの中身を書き換えると、これら3つの$変数が指し示すものも変わります。

これは例えば、

http://www.yahoo.co.jp
http://www.yahoo.co.jp/
http://www.yahoo.co.jp/index.html
の3つのURLが指すものはどれも同じコンテンツ(ヤフーのトップページのhtmlファイル)であるのと似ています。
ヤフーがトップページのコンテンツ(=index.htmlファイル)を書き換えると、これら3つのURLが返す結果が変わります。
リファレンス($reference_to_list)とデータ(@list)の関係もこれと同じことです。


ちなみにリファレンスをprint出力すると下記のような結果になります。

print $reference_to_list;
出力: ARRAY(0x1829884)
この" ARRAY(0x1829884)" が、@listを指し示すアドレスです。
@listはコンピュータのメモリ上に存在し、そのメモリ上のアドレスが" ARRAY(0x1829884)"なのです。

ちなみに、$reference_to_list2, $reference_to_list3をprint出力した場合も全く同じ結果が出ます。

仕事で、ある大学のWEBサイトの一部をPerl/CGIで構築することになりました。 その大学では、未だにPerlのバージョンが5.008なのです。 一瞬見間違いかと思ってよく見たら、やっぱり5.008なんです。(涙) Wikipediaで調べたら、Perl5.005_04が出たのが何と1994年!? 私は普段Perl5.8を使っているんですが、5.8用に書いたスクリプトが、はたして5.0上で動くのか?? Googleでいくら検索しても、5.8と5.0の違いを説明したサイトは出てきません。 さすがに1998年のPerlに関する情報をWebで探すのは無理か。。。 Perl5.6についての解説記事はいろいろ出てくるのに、5.0に関する情報は皆無。(><) とりあえず、5.0はUnicodeに対応してないようなので、EUCで作ることにしました。 で、CGIスクリプトは何とかできました。 しかし、納品前にやはり5.0で動作検証しないといけません。 途方にくれながら、手元にあった「すぐわかるPerl」という本をペラペラめくっていると・・・ あった! 「付録B UnixにPerlを入れてみよう」 という章に、Perl5.005_03にインストール方法が! しかも懇切丁寧な解説! これぞ天の助け!!(^^)/

Perl5.005_04をソースコードからのインストールに挑戦

小躍りしながら早速CPANにアクセスして、perl5.005_04.tar.gzをダウンロード。
いざ、解凍。
% gunzip < perl5.005_04.tar.gz | tar xvf -
(コマンドの意味は一切わかりまへん(**) )
いろいろ解凍される。

終わったら、ディレクトリを移動して
% cd perl5.005_04
% rm -f config.sh
% sh Configure

もはや私にとっては暗号でしかない。。。

which of thease apply, if any? [linux]
いろいろ質問されるが、ほとんどデフォルトでいいらしいので、Enterキーをひたすら押す。

Installation prefix to use? (~name ok) [/usr/local]
ここは自分のホームディレクトリを指定するのがよいらしいので、そうする。
あとはひたすらEnterキーを連打。
終わったみたいなので、次はコンパイル。

% make
ここで、エラー発生!ひえ〜
make: *** `miniperlmain.o' に必要なターゲット
`<\343\202\263\343\203\236\343\203\263\343\203\211\343\203\251\343\202\244\343\203\263>'
を make するルールがあり ません. 中止
ひえ〜全然意味わからん。。。 エラーメッセージでGoogle検索しまくると、このページにたどり着く。 Perl の make 時に miniperl でエラーになる場合の対処方法 ふむふむ。 で、おそるおそる ./config.sh の内容を書き換える。
ld='gcc'
libs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
そしてmake
% make
をを!動いた!
% make test
エラーが2個出たけどうまく行ったっぽい?
$ bin/perl -v

This is perl, version 5.005_04 built for i686-linux

Copyright 1987-1999, Larry Wall
おおお!!感激!! ラリーさまのお名前が!! 無事インストール成功(^^)V
追記
私は勘違いをしていました。 Perl5.008 = perl5.8だったようです。 従って、Perl5.005 = Perl5.5ということになります。 私はPerl5.005をインストールする必要はなかったことがわかりました。 アホですいません。 しかし、インストール方法自体は誰かの役に立つかもしれないので残しておきます。

以前、ハッシュスライスを使うやり方を紹介しました。

今回はmap演算子を使ったやり方です。

use strict;
use warnings;

my @keys = ("a", "b","c");
my @values = (1,2,3);

my %hash = map { $keys[$_] => $values[$_] } (0..$#keys);


出力結果
 'c' => 3,
'a' => 1,
'b' => 2


解説

map 演算子のブロックの中で、2つの値をペアで記述するのがポイントです。


$keys[$_] => $values[$_]
の代わりに、
$keys[$_] , $values[$_]
と書いてもOKです。


関連記事
[Perl] 2つ配列から1つのハッシュを作る方法 (ハッシュスライス)

2つの別々の配列を、それぞれキーの集合体、値の集合体としてとらえて、1つのハッシュに合成する方法。

my @keys = ("a", "b", "c");
my @values = (1, 2, 3);

my %hash;
@hash{@keys} = @values;


%hashが@hashと書かれていて、一瞬、アレ?そんなのアリ?と思ってしまいます。
これはハッシュスライスというものだそうです。


%hashの出力結果:

'c' => 3,
'a' => 1,
'b' => 2

[Perl] -w とuse warnigs;の違いについて   はてなブックマークに登録  

perl -w と use warningsの違いがずっとわからなかったのですが、dankogaiさんの超わかりやすい解説を見てやっと理解できました。

要約すると、

-wは.plには有効でも.pmには有効ではない

use warnings;ということは、no warnings;も存在する(中略)。局所的に警告を止めることも出来る。

ということだそうです。

ナルホド!!

というわけで私も今日からuse strict;に続けてuse warnings;を書こうと思います。
danさんに感謝!!

Net::FTPがすごい便利です。

これを使うと、FTPのアップロードやダウンロードの自動化はもちろんのこと、
FTPサーバの中をのぞいてフォルダ・ファイルの全リストを取得、なんてことも簡単にできてしまいます。

便利すぎて死にそう!!

手元のWindowsマシンからActivePerlでリモートのFTPサーバに接続してみました。

use strict;
use Net::FTP;

my $ftp = Net::FTP->new("my.host.name", Debug => 0 , Passive => "true"); # 接続
$ftp->login("username", "password"); # ログイン

my @dir = grep /^d/, $ftp->dir; # ← フォルダ一覧をdirコマンドで取得
my @dir_names_full = @dir[2..$#dir]; #  自フォルダと親フォルダ("."と"..")を除く。
my @dir_names_short = map { (split)[8] } @dir_names_full; # フォルダ名のみを取得

$ftp->quit;

# 出力してみる。
print "$_\n" for @dir_names_full;
print "\n";
print "$_\n" for @dir_names_short;


出力結果
drwxrwx---   2 dqn      vchkpw       4096 Aug 26  2006 Maildir
drwxrwxrwx 3 dqn hpusers 4096 Aug 13 2007 db
drwxr-xr-x 2 dqn hpusers 4096 Jun 18 07:04 log
drwx---r-x 33 dqn hpusers 4096 Mar 31 00:32 public_html

Maildir
db
log
public_html


参考

Perl初心者が最初につまづくのがこのuse strict。
Perlスクリプトの冒頭に、呪文のように必ず登場しますよね。

初心者向けに、超わかりやすく解説してみます。

use strictとは一体何?

Perlを書くときに、必ず最初に書くおまじないだと思ってください。
Perlでは、スクリプトの冒頭に"use strict;"と書くのが推奨されています。

書き方
#!/usr/local/bin/perl
use strict;

use strictを使うメリット

端的に言うと、
バグが減る。

use strictを使うと、変数を宣言するとき(=ある変数を最初に使うとき)にmyを付けるのが必須になります。

use strict;
my $name = "オラ悟空";
print $name;

以下の2つのコードはエラーになります。
use strict;
print $name; # $nameはmyで宣言されてないのでエラー

use strict;
my $name = "オラ悟空";
print $namae; # $namaeはmy宣言されていないのでエラー

つまり、変数のタイプミスをPerlが教えてくれるのです。
use strictしておかないと、ミスに気づかないままプログラムがおかしな挙動をしてしまいます。
use strictはこのようなバグを防いでくれます。

なお、"use"の意味についてはここでは解説しません。
もっとPerlを書いたり勉強したりするうちにわかる日が来ると思います。

関連記事: [Perl] use strictを導入してみた

substr(文字列, 開始位置, 文字数)

substr("I love you",2,4);

結果: love

substr("I love you",2);

結果: love you

substr("I love you",0,-4);

結果: I love


このアーカイブについて

このページには、2008年6月以降に書かれたブログ記事のうちPerlカテゴリに属しているものが含まれています。

前のアーカイブはPerl: 2008年5月です。

次のアーカイブはPerl: 2008年7月です。