古い記事
ランダムジャンプ
新しい記事
SUFARY を用いたテキスト検索 CGI(行単位、プレフィックスマッチ)の最近(というか数年前)書き直した雛形を公開。言語は Perl です。

- SUFARY::search()ではなく SUFARY::range_search() を使うと検索結果インデックスポインタの配列が生成されないのでメモリ的にお得!
- SUFARYの返し値は内部文字列になってない。注意。
- Exactにマッチさせたい場合は、例えば各行を「^エントリ文字列\t...$」というフォーマットにし、内部で末尾に "\t" を付加したキーで検索します。定番処理です。
- 簡単なページ送り機能付き!
- テンプレート(__DATA__以降)に日本語文字を入れる場合は、「use utf8;」をコメントアウトするか、「my $template = encode('utf-8', ...);」にする。

コード

sals.cgi
#!/usr/bin/perl -T
use strict;
use warnings;
use CGI;
use SUFARY;
use Encode;
use URI::Escape;
use HTML::Template;
use utf8;
binmode STDOUT, ":utf8";

my $fn = "test-dic.txt";
my $sa = SUFARY->new($fn);

my $q = new CGI;
my $key = $q->param('key');
my $start = $q->param('start') || 1;
my $num = $q->param('num') || 10;

my $r_ref = search($sa, $key);

my $template = join("", <DATA>);
my $t = HTML::Template->new(scalarref => \$template,
			    global_vars => 1,
			    die_on_bad_params => 0);
$t->param(key => $key);
$t->param(ekey => URI::Escape::uri_escape($key));
$t->param(results => $r_ref->{cont}) if %$r_ref;
$t->param(pre => $r_ref->{pre}) if %$r_ref;
$t->param(nex => $r_ref->{nex}) if %$r_ref;

print $q->header(-charset => 'UTF-8'), decode('utf-8', $t->output());

sub search {
    my ($sa, $key) = @_;
    return {} if $key eq "";

    my ($left, $right) = $sa->range_search($key);
    return {} if not defined $left and not defined $right;

    my $n = $right - $left + 1;
    my $from = $left + $start - 1;
    return {} if $right < $from;
    my $to = $from + $num - 1;
    $to = $right if $to > $right;

    my @rv;
    for (my $k = $from; $k <= $to; $k++) {
	my $pos = $sa->get_position($k);
	my $str = $sa->get_line($pos);
	push @rv, {line => $str};
    }

    my $pre = ($start - $num > 0) ? $start - $num : 0;
    my $nex = ($start + $num <= $n) ? $start + $num : 0;

    return {cont => \@rv, pre => $pre, nex => $nex};
}

__DATA__
<html lang="ja">
<head>
<meta http-equiv="Content-Type" contet="text/html; charset=UTF-8">
<title></title>
</head>
<body>
<h1></h1>

<form>
<input type="input" name="key" size="30" value="<TMPL_VAR name=key>">
<input type="submit">
</form>

<TMPL_IF name=results>
<TMPL_LOOP name=results>
<TMPL_VAR name=line><br>
</TMPL_LOOP>
</TMPL_IF>

<TMPL_IF name=pre>
<a href="?key=<TMPL_VAR name=ekey>&start=<TMPL_VAR name=pre>">&lt;&lt;</a>
</TMPL_IF>
<TMPL_IF name=nex>
<a href="?key=<TMPL_VAR name=ekey>&start=<TMPL_VAR name=nex>">&gt;&gt;</a>
</TMPL_IF>

</body>
</html>

データの準備

要SUFARY。
% tail -5 test-dic.txt
龍尾神社
龍滕 LONG TENG(赤坂)
1万円入りま〜す
1日なのでお休みです
Tシャツ・ラブ・サミットでTシャツを買ってきた!
% mkary -l test-dic.txt
「-l」オプションで行頭にインデックスを張ります。

実行例

画像

参考

- SUFARY 臨時復旧ページ http://ta2o.net/tools/sufary/
(SUFARYの入手はここから。)
- [を] 郵便番号検索 ybks 公開、というか再公開[2006-04-23-2]
(古い雛形を元にしたもの。)
- [を] さくらの500円レンタルサーバーで SUFARY.pm を動かす[2008-08-20-3]
(インストール方法の一例。)
- [を] SUFARY Hacks (1) 最長の繰り返し文字列を探す[2006-04-24-2]
(SUFARY Hacks の続きを書こうかな…。)
この記事に言及しているこのブログ内の記事