Hatena::Groupbluespear

bluespearの勉強メモ

2007-10-14

[]tie関数: dbmopenの代わりに使う 15:22

マニュアル http://perldoc.jp/docs/perl/5.8.8/perltie.pod

tieはオブジェクト変数を結びつけるとのことで、完全に理解するにはPerlでのオブジェクトの知識が要る様子。まだわかっていないので、dbmopenの代わりに使うところまで調べた。

使い方

#!perl
use strict;
use warnings;
use DB_File;
use Fcntl;   #O_CREAT, O_RDWRなどに必要

#tie VARIABLE, CLASSNAME, LIST
tie(my %DATA, 'DB_File', 'dbm_filename', O_CREAT|O_RDWR , 0600, $DB_HASH);
%DATA = ("test1" => 10, "test2" => 175, "test3" => 483);
while (my($key, $value) = each %DATA){
  print "$key has $value\n";
}
untie %DATA;

tie自体の引数は3つ。

  1. 結び付けられる変数
  2. 結びつけるオブジェクト
  3. オブジェクトに渡す引数リスト

結び付けられるオブジェクトはDESTROY, FECH, STOREなどのメソッドを実装しておく必要がある。

untieでdbmcloseと同じく結びつきを解除。

DB_File使用時の第4引数以降

use Fcntl により、本来数字で指定するファイルオープンフラグを名前で指定できる。

O_RDONLY : 読み込みモードオープン

O_RDWR : 読み書きモードオープン

O_CREAT : ファイルが無ければ作成する

O_EXCL : ファイルが既に存在する場合はエラー

O_SYNC : 同期書き込みモード

O_TRUNC : オープンした時にファイルを空にする

http://memo.blogdns.net/cgidbm.html

データベースの種類は3つ。

DBMファイルの種類

Berkeley DB, GDBM, NDBM/SDBM といった種類がある。GDBMはGnu版DBM。NDBMはBSDシステムでしか使えない。SDBMはデータサイズに制限がある。

Berkeley DBかGDBMをつかっておけばいい?

参考URL

*1:平衡木。常にソートされている。原理は「プログラミングの宝箱 アルゴリズムデータ構造」p194あたりや、http://ja.wikipedia.org/wiki/B%E6%9C%A8 参照

GuwashiGuwashi2007/10/17 01:59ほー、最近はPerlをやってるのね :)
Perlは... Perl4までしかわかんない old type だよ :P

bluespearbluespear2007/10/17 13:43あっちゃこっちゃと手を出してるので、根本的に全然技術が身について無い気がしますが、新しいのに手を出すのが楽しくてw 入門書を読むのが趣味になってるんじゃないか疑惑。
Perlはバージョンごとに仕様が結構変わってるらしいですね。6が出たらどうなるんだろう。いろんなBlog見ても高度すぎてわからない:)

2007-10-13

[]ソートブルーチンを使ったsort 15:23

sortでASCII順にソートできるが、それ以外の方法でソートするには、ソートブルーチンを渡せばよい。

sub by_number {
  if ($a < $b) { -1 } elsif ($a > $b) { 1 } else {0}
}
my @result = sort by_number @some_numbers;
# @result = sort @some_numbers; とするとASCIIコード順にソート

ソートブルーチンには$aと$bが自動的に用意される。ソート済みリストになったときに$aが$bより先に現れるべきなら-1,$bが先なら1,比較できないときは0を返す。上の例なら、($a < $b)のとき$aが先に現れるので-1を返す。

上のコードは <=>を使って簡単に書ける。*1

my @result = sort { $a <=> $b } @some_numbers;
@result = sort { $b <=> $a } @some_numbers;  #逆順ソート

<=>は各演算子が成り立つときに-1,0,1を返す、という風に見ると覚えやすい。<=>演算子は左右の値しか見ていないので、$a $bを入れ替えれば逆順にソートできる。

<=>の文字列版はcmp。単体ではデフォルト動作だから使わないが、組み合わせで使う。

sub case_insensitive { "\L$a" cmp "\L$b" } #大文字小文字を区別しない

ハッシュを値でソートして~

ハッシュ自体はソートできない!出てきたリストソートして"ほにゃらら"する。

my %score = ("barney" => 195, "fred" => 205, "dino" => 30);
my @winners = sort by_score keys %score;
sub by_score { $score{$b} <=> $score{$a} } #ハッシュの値で降順にソート

複数のキーを使う場合は or で繋げる。つまり前の式が比較できない=0だと後ろの式が評価される。

sub by_score_name {
  $score{$b} <=> $score{$a} or
  $a cmp $b
}

[]DBMハッシュとDBMファイル 15:55

単純なデータベースとして、DBMファイルをDBMハッシュとして扱える。ハッシュと同じように使えるのが特徴。本格的なデータベースを使うならDBIモジュールを使う。

DBMハッシュの使い方

ファイルを開くのと似たようにdbmopenでDBMファイルを開き、あとはハッシュと同じように使う。ハッシュの中身を替えればデータベースにも反映される。deleteでその要素を削除出来る。閉じるにはdbmclose。

dbmopen(%DATA, "database_filename", 0644) or die "Cannot create database_filename: $!";
#0644は新しく作る場合のパーミッション。
#undefでファイルが無いときに新規作成をしない。

$DATA{"fred"} = "bedrock";
delete $DATA{"barney"};
#keysはハッシュ全体をスキャンするので使わない方が良い
#変わりにeach関数で少しずつ見ていく
while(my($key, $value) = each(%DATA)) {
  print "$key has value of $value\n";
}
dbmclose(%DATA);

Cプログラムで管理されているDBMファイルを扱う場合は、文字列末尾のヌル文字に注意。この場合は、DBMファイルに入れる文字列にはヌル文字を挿入し、得た文字列からはヌル文字を削除する。

複数からの並列アクセスを考慮する場合はPerlクックブック参照とのこと。http://www.unix.org.ua/orelly/perl/cookbook/ch14_06.htm ここら辺?

[]書き戻し編集: $^I と<> 16:44

ダイヤモンド演算子と$^Iを使うことで、簡単にファイル編集できる。

$^I文字列がセットされると、ダイアモンド演算子は出力先を読み込み元ファイルに切り替える。$^Iにセットされた文字列がバックアップファイル名に追加される。$^Iに空文字がセットされた場合は、バックアップファイルを取らない。*2

@ARGV = glob "fred*.dat";
$^I = ".bak";
while(<>){
  s/foo/bar/g;
  print;
}

コマンドラインから書き戻し編集

上の例と同じことを、次のようにコマンドラインから行える。

perl -p -i.bak -w -e 's/foo/bar/g' fred*.dat
  • -pは while (<>) {print;} というコードを用意する。(-nはこれのprint無し版)
  • -iは$^Iに.bakをセットする。-iだけなら空文字セットと同じ。
  • -eの後ろに実行する文を書く。Perlは渡された文字列をPerlコードとして認識する。なのでシェルに変な風に解釈されないようにする。セミコロンで複数行も書ける。

*1:スペースシップ演算子:スターウォーズの敵タイファイターに似てるから

*2:正確には、$^Iにセットされていると、元ファイル改名して、元ファイルと同じファイル名で新しく書き出す、という処理。

2007-10-11

[]tr///による変換 20:36

tr/検索リスト/置換リスト/cds

検索リストにある文字を対応する置換リストの文字に変換する。 =~ や =! で適用する文字列を指定(デフォルトは$_)。

tr/a-z/A-Z/のように文字範囲を使用可能だが、\dといった正規表現文字クラスは使えない。

置換または削除が行われた文字数を返す。

マニュアルhttp://perldoc.jp/docs/perl/5.8.8/perlop.pod

オプション

/c検索リストを補集合とみなす
/d検索リストにあって置換リストに対応しない文字は削除する
/s置換された文字が重なったときに圧縮する

\dが指定されていないとき、置換リストが検索リストより短いときは置換リストの最後の文字が繰り返されているものとして扱われる。置換リストが空文字のときは検索リストと同じになる。

$cnt = tr/*/*/;        #$_の*数を数える
$cnt = $sky =~ tr/*//; #$strの*の数を数える
tr/a-zA-Z/ /cs;        #アルファベット以外を1つのスペースに
                       #abc123dfg -> abc dfg

[]ヒアドキュメント 23:51

複数行にまたがる文章を出力するときに使う(?)

マニュアルhttp://perldoc.jp/docs/perl/5.8.8/perlop.pod

ヒアドキュメント終了を表す識別子を<<の直後に置く*1。識別子は行に単体で置く。識別子のクォートによって変数展開などが変わる。''は変数展開されない。``はそのコマンドを実行して出力を返す。

my $score = 100;
#The score is 100
print <<EOF;
The score is $score
EOF
print <<"EOF";
The score is $score
EOF

#The score is $score
print <<'EOF';
The score is $score
EOF

print <<"foo", <<"bar";
I said foo.
foo
I said bar.
bar

*1:クォートされていれば空白文字を挟んでもOK

2007-10-10

[]perldoc日本語15:17

http://perldoc.jp/

Perldocを日本語訳するプロジェクトPerlコアドキュメントから、モジュールのDocも翻訳されている。ブラウザからも閲覧可能。プロジェクトページはhttp://perldocjp.sourceforge.jp/

基礎 perldata, perlvar, perlsyn, perlop, perlsub

実行 perlrun, perldebug

関数 perlfunc

オブジェクト perlref, perlmod, perlobj, perltie

データ構造 perlref, perllol, perldsc

モジュール perlmod, perlmodlib, perlsub

正規表現 perlre, perlfunc, perlop, perllocale

perl5への移行 perltrap, perl

Cとのリンク perlxstut, perlxs, perlcall, perlguts, perlembed

その他 http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz

(man-page ではありませんが有用な、Perl のテクニックに

関するコラム集です)

http://perldoc.jp/docs/perl/5.8.4/perlfaq3.pod

[]文字列操作(index, substr) 16:49

正規表現を使うまでも無いときに簡単に使える。実際使う機会はあまり無いらしい。

index / rindex

indexは文字列から部分文字列を探し、その場所を数値で返す。配列のように0等で。返すのは最初に見つけた場所。第3引数は、サーチを始める場所。

$where = index($big, $small);
#some/slash/is
#01234567890
$where = index("some/slash/is", "/"); #4
$where = index("some/slash/is", "/", 5); #10

rindexは文字列の後ろからサーチを開始し、最初に見つかった場所を返す。値はindexと同じく先頭から数えた数。

substr

substrは文字列の一部を長さを指定して取り出す。

引数は文字列値、開始位置(先頭が0)、部分文字列の長さ。開始位置には負の値も使用可能。文字列値が変数(左辺値)の場合、代入の形で指定した部分だけを置き換えられる。

$part = substr($long_string, $initial_position, $length);
substr($string, index($string, "Hello"), 5) = "Good bye";
#部分文字列より長い置き換えの場合、文字列が自動的に伸縮する。

[]system, exec, 逆クォート 17:04

systemは子プロセスを呼び出す。execはPerlプロセス自身が実行する(実行が終わればそのままPerlには戻らず終了)。逆クォートは出力を文字列として受け取る(リストコンテキストだと1行ずつのリストを返す)。

多数の引数を渡す場合は、コンマで区切る他引数形式を用いる。

system "data";
exec "data";
my $data = `data`;

2007-10-09

[]式修飾子 20:42

式の後ろにifなどの制御修飾子を書ける。ただし、修飾子の両端には単一の式しか置けない。

foreachの制御変数は常に$_になる。

print "$_ -> $value\n" if defined $value;
$i *= 2 until $i > $j;
print " ", ($n += 2) while  $n < 10;
printf "%20g\n", $_ foreach @nums;

[]forとforeachは同じ 20:42

forの方が単語が短いので、forを使うことが多いらしい。

for (1..10) {  #foreachでもOK
 print "$_\n";
}

[]grepmap 22:08

grepは"ブロックか単一の式が真を返す要素からなるリスト"を返す。

@matching_line = grep { m/^searching/ } <FILE>;
@matching_line = grep m/^searching/, <FILE>;

mapは"各要素にブロック化単一の式を適用した要素からなるリスト"を返す。

my @formated_data = map { foo($_) } @data;
print "data is : \n", map { sprintf("%20s\n", $_) } @formated_data;
#print "data is : \n", map { sprintf("%20s\n", foo($_)) } @data;
#もあり
print "some powers of 2 : \n", map "\t". (2 ** $_) ."\n", 1..15;

grepmapインデックス変数$_はリストの値へのエイリアスなので、$_に対する変更は、元のリストへの変更になる。(これはforeachも同様)

grepは式はブール値として解釈されるが、mapではリストコンテキストで解釈されるので複数の値を返せる。

[]スライス 01:15

リストから任意の要素を任意個返す。ハッシュも可能。

my ($size, $mtime) = (stat $somefile)[7, 9];
my @nums = @nanika[9, 5, 3, 1]; #@はリスト
my $num = $nanika[8];           #$はスカラー
@nanika[1, 5] = ("new", "re");  #特定の要素の更新も可
my @three_score = @score{qw/ fred barney dino /}; #リストを返すから@
@score{ qw/ fred barney dino / } = (198, 201, 98); #代入も可
#($score{fred}, $socre{barney}, $score{dino}) = (198, 201, 98);と同じ