#!/usr/local/bin/perl # -------------------------------------------------------------------- # # btree-test.pl -- DB_File モジュールによる前方一致検索 # Copyright 2000 Kawasaki Yusuke , Kappe Inc. # -------------------------------------------------------------------- # =tuc 【概要】 Berkley_DB (DB_File) の BTREE 機能を用いると、連想配列のキーを 前方一致で指定して、それにマッチする全てのキー&値を取り出せる また BTREE なので、sort しなくても自動的にキーがソートされてる 【結果】 all keys and values: ← sort 指定しなくてもソートされている 'nec' = 'Lavie' 'pana' = 'Letsnote' 'sharp' = 'Mebius' 'sony' = 'VAIO' 'sotec' = 'eOne' 's' matches 3 keys. ← s で始まるキーのみ取り出した場合 'otec' = 'eOne' 'harp' = 'Mebius' 'ony' = 'VAIO' 'so' matches 2 keys. ← so で始まるキーのみ取り出した場合 'tec' = 'eOne' 'ny' = 'VAIO' 'sony' matches 1 keys. ← sony で始まるキーのみ取り出した場合 '' = 'VAIO' 'hitachi' matches 0 keys. ← hitachi で始まるキーは存在しない 【補足】 get_lmatch_hash() 関数の $key = $1; の行をコメントアウトすると、 マッチしたキーを取り出したときに、マッチしていた部分も保存される デフォルトでは、マッチしていた部分は削除している 【ダウンロード】 http://www.kawa.net/works/perl/btree/btree-test.pl =cut # -------------------------------------------------------------------- # use strict; use DB_File; use Fcntl; &main(); # -------------------------------------------------------------------- # sub main { my $tied; # 川崎はリファレンスと my が好きなので(笑) my $iname = undef; # 普通は "data.btree" 等DBファイル名を指定 # ファイル名 undef を指定するとメモリ上で動く # 今回はテストなので、メモリ上でいいでしょう my $otype = Fcntl::O_RDWR()|Fcntl::O_CREAT(); # 読み書き可能で開く my $omode = 0666; # 作成時は rx-rx-rx- my $dbopt = new DB_File::BTREEINFO(); # BTREE モードで開く my $dbobj = tie( %$tied, "DB_File", $iname, $otype, $omode, $dbopt ) or die "$! '$iname'"; # 開けなければエラー $tied->{pana} = "Letsnote"; # 適当に値を代入する $tied->{sotec} = "eOne"; $tied->{sharp} = "Mebius"; $tied->{sony} = "VAIO"; $tied->{nec} = "Lavie"; print "all keys and values:\n"; foreach my $key ( keys %$tied ) { # 全てのキーを取り出す printf( "\t'%s'\t= '%s'\n", $key, $tied->{$key} ); } foreach my $left (qw( s so sony hitachi )) { # 前方一致で取り出す my $hash = &get_lmatch_hash( $dbobj, $left ); printf( "'%s' matches %d keys.\n", $left, scalar keys %$hash ); foreach my $key ( keys %$hash ) { printf( "\t'%s'\t= '%s'\n", $key, $hash->{$key} ); } } } # -------------------------------------------------------------------- # sub get_lmatch_hash { my $db = shift; # tie( %hash, "DB_File ) の返り値 my $okey = shift; # 前方一致マッチングしたいキー my $key = $okey; # 最初の seq() で指定するために my $value = ""; # seq() 用のメモリ確保? my $opt = DB_File::R_CURSOR(); # 前方一致指定オプション my $hash = {}; while ( 1 ) { # 1回目のみ=前方一致で $key, $value を取り出す # 2回目以降=B木の次の $key, $value を取り出す # 返り値が真の場合、DBの末尾なので終了 $db->seq( $key, $value, $opt ) and last; # 本当にキー前方一致しているか確認する last unless ( $key =~ /^\Q$okey\E(.*)$/s ); $key = $1; # 指定キーの右側を取り出す $hash->{$key} = $value; # ハッシュに突っ込む $opt = DB_File::R_NEXT(); # 次のキーを取り出すオプション } scalar keys %$hash ? $hash : undef; } # -------------------------------------------------------------------- #