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

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

まずは配列。

リファレンス入門

Perl入門者がつまづきやすいリファレンスについて、続・初めてのPerl 改訂版(通称アルパカ本)を下敷きにしてわかりやすく解説してみます。
仕事で、ある大学のWEBサイトの一部をPerl/CGIで構築することになりました。

forとforeachは、何が違うのか?

実は、違いはありません。
まったく同じです。
リャマ本こと「初めてのPerl」の第10章にもこう書いてあります。

Perl文法の中では、キーワードforeachはキーワードforと完全に等価です。
つまり、プログラムの中で、forと書いてもforeachと書いても、Perlはそれを同じものとして扱うのです。


したがって、下記の2つのループは同じ動作をします。

use strict;
use warnings;

my @array = ("x", "y","z");

foreach(@array){
print $_."\n";
}

for(@array){
print $_."\n";
}

で、どちらを使えばよいのかというと、


文字数が少ないFORをお勧めします!
(ダジャレではない)

関連記事
Perl再入門 | 超簡単!for,foreachの使い方 Perl再入門 | for,foreachはループ対象の配列を書き換えます。ご注意。

配列に対してforやforeachでループ処理をする際に、制御変数の中身を変更すると、元の配列の中身も変更されてしまいます。


知らないと思わぬ損をするので、気をつけましょう。
私は今まで知りませんでした。(><)

use strict;
use warnings;

my @array = ("x", "y");

for (@array){
$_ = "z";
}

print "@array";

出力結果:
z z


なお、以下のような書き方でも同じ結果になります。
for my $a (@array){
$a = "z";
}

関連記事
Perl再入門 | 超簡単!for,foreachの使い方

forやforeachは、配列の全要素を対象としたループ処理をするときに使います。

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

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

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

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

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

便利すぎて死にそう!!

以前に書いた記事「[WSH]VBSからAccessのアクションクエリを実行する方法 (ADO) 」では、アクセス側であらかじめ作っておいたアクションクエリをVBSから実行する方法を紹介しました。

Excel VBAで、Writeステートメントを使ってCSV出力すると、日付が #2008-01-01# のような形式になってしまいます。
このCSVをAccessにインポートするのは大変です。
以下のような自作関数を使って変換しましょう。

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

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

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

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

結果: love

substr("I love you",2);

結果: love you

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

結果: I love


hidemaru-replace.JPG


メニュー > 検索 > 置換

で、

・検索ボックスに下記を入力
^(.*) (.*) (.*) ¥[(.*)¥] "(.*)" (.*) (.*) "(.*)" "(.*)"$

・置換ボックスに下記を入力
¥1¥t¥2¥t¥3¥t¥4¥t¥5¥t¥6¥t¥7¥t¥8¥t¥9

・正規表現にチェックを入れる。

・置換する。



これだけでOK。

置換後の区切りは、タブ区切りにしておきました。
その方が後でいろいろ扱いやすいみたいです。

参考:XREAのアクセスログ(LOG)をCSVに一発変換するための正規表現

現在のプレゼンテーションファイルの場所(パス)を取得する方法。

MsgBox ActivePresentation.Path 

WSHで動くJScriptでは、JavaScriptのpromptのような機能がありません。
なので、VBSのInputBoxを呼び出して使います。

ExcelやPowerPointやWordでVBAを実行するときに、マクロの実行時間を測定する方法。

ストップウォッチが手元にないときはこのコードを使いましょう。

3桁の乱数のみで構成される簡易パスワードを、
Accessのクエリで発生させる方法です。

普通にrnd関数を使うと、同じような乱数系列が繰り返されてしまいうまく行きません。
(昨日出たのと同じ数字がまだ出てたりする)

Randomizeステートメントとかを駆使すると回避できるらしいですが、ヘルプを見てもよくわかりませんでした。

そこで、システム時刻をあらわすTime()関数と組み合わせたらとうまく行きました。

クエリのSQLビューで、以下のコードを書いて実行すればOK。

SELECT Right(CLng(Time()*10000000*Rnd()),3) AS 乱数; 


なお、時刻のコンマ何秒という数字は、それ自体が乱数のようなものなので、Rnd関数を省いても一応動きます。

SELECT Right(CLng(Time()*10000000),3) AS 乱数;

これを乱数と呼べるのかはわかりませんが。(^^;


人気記事

このアーカイブについて

このページには、2008年6月に書かれたブログ記事が新しい順に公開されています。

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

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

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

最近の人気記事