C ライブラリリファレンスガイド ( 未完成 )

$Id: libsufary.html,v 1.3 2000/07/14 11:30:50 tatuo-y Exp $
山下 達雄 Yamasita, Tatuo, 高岡 一馬 Takaoka, Kazuma


Notation
$SUFRAY : SUFARYパッケージを展開したディレクトリを表します。

はじめに

この文書では、SUFARY の C ライブラリの使い方について解説します。 array ファイル、DocID ファイルについてご存知ない方は、 先に「検索用ファイル作成ガイド」をお読み下さい。

コンパイルの方法

C プログラムから SUFARY を使うには、まず sufary.h を インクルードします。

// sample.c //

#include <stdio.h>
#include <stdlib.h>
#include "sufary.h"
...

そして、以下のようにコンパイルします。

// コンパイル //

%  $SUFARY/libtool --mode=link gcc -I$SUFARY/lib -o sample sample.c \
$SUFARY/lib/libsufary.la

 or

%  gcc -I$SUFARY/lib -o sample sample.c $SUFARY/lib/libsufary.a

$SUFARY/src/ に C ライブラリを用いたプログラムが ありますので、参考にして下さい。

文字列検索

関数:ファイルの開閉

SUFARY *sa_open(char *text_file_name, char *array_file_name)
検索のためにテキストファイルと array ファイルを開きます。 引数にそれぞれのファイル名を指定します。 array ファイル名に NULL を指定すると、 array ファイル名は「テキストファイル名 + ".ary"」 になります。

// 例 //

/* data.txt -> data.txt.ary */
SUFARY *ary = sa_open("data.txt", NULL);
ファイルを開くのに成功した場合は、 SUFARY 型変数へのポインタを、失敗した場合は NULL を返します。 SUFARY 型変数は検索時に必ず必要になります。
void sa_close(SUFARY *ary)
テキストファイルとarrayファイルを閉じます。
SA_INDEX sa_get_array_size(SUFARY *ary)
array ファイルに含まれる要素の数を返します。
SA_INDEX sa_get_text_size(SUFARY *ary)
テキストファイルの大きさを返します。

関数:文字列検索

SUF_RESULT sa_find(SUFARY *ary, SA_INDEX left, SA_INDEX right, char *keyword, int keyword_length, int base_txt_skip)
キーワード検索を行ないます。 検索結果は SUF_RESULT 型変数として返されます。

// SUF_RESULT //

typedef struct {
    SUFARY *suf;
    SA_INDEX left;
    SA_INDEX right;
    SA_STAT stat;
} SUF_RESULT;

// 例:一般的な使い方 //

char *key = "hello";
SUF_RESULT sr = sa_find(ary, 0, sa_get_array_size(ary) - 1, key, strlen(key), 0);
キーワードの見つかった場所は範囲で表されます。 これらは sr.leftsr.right に格納されます。 キーワードにマッチする文字列が見つからなければ sr.stat に FAIL が、 見つかれば SUCCESS が格納されます。

関数:検索結果を取り出す

suffix array ( array ファイル ) の各要素にはテキスト位置情報 ( テキストの先頭からの文字数 ) が格納されています。 検索結果は suffix array の添字の情報だけです。 文字列として扱うためには、 これをテキスト位置、文字列ポインタに変換する関数が必要となります。

SA_INDEX sa_aryidx2txtidx(SUFARY *ary, SA_INDEX i)
suffix array の添字をテキスト位置に変換します。
char *sa_aryidx2txtptr(SUFARY *ary, SA_INDEX i)
suffix array の添字を文字列ポインタに変換します。
char *sa_txtidx2txtptr(SUFARY *ary, SA_INDEX i)
テキスト位置を文字列ポインタに変換します。

テキスト位置を元に検索結果を文字列として取り出す関数もいくつか 用意してあります。

SA_STRING sa_seek_context_lines(const SUFARY *ary, char *pos, int bkwrd, int frwrd)
pos を含む一行と、その前の bkwrd 行、 後の frwrd 行を SA_STRING 型として取り出します。

// SA_STRING //

typedef struct {
    char *ptr;
    size_t len;
} SA_STRING;
SA_STRING sa_seek_context_region(const SUFARY *ary, char *pos, const SA_STRING begin_tag, const SA_STRING end_tag)
単純なテキストエリア取り出し処理を行います。 テキスト位置で指定された周辺の指定されたタグ ( begin_tag, end_tag ) で囲まれた文字列を取り出します。 指定されたテキスト位置の前後をスキャンしてタグを探すという単純な方法なので、 DocID ファイルは必要有りませんが、 DocID ファイルを用いる方法より遅くなります。
size_t sa_copy_region(char *dst, const SA_STRING src)
文字列 strdst にコピーし、末尾にナル文字 を追加します。dstsrc.len + 1 バイト確保 されている必要があります。
char *sa_dup_region(const SA_STRING src)
malloc でメモリを確保して、文字列 strコピー し末尾にナル文字を追加します。

サンプルプログラム

// sample.c //

#include <stdio.h>
#include <stdlib.h>
#include "sufary.h"

int main(int argc, char *argv[])
{
    SUFARY *ary;
    SUF_RESULT sr;

    ary = sa_open(argv[2], NULL);
    if (ary == NULL)
        exit(1);

    sa_set_debug_mode(1);

    sr = sa_find(ary, 0, sa_get_array_size(ary) - 1, argv[1], strlen(argv[1]), 0);
    printf("%ld %ld\n", sr.left, sr.right);

    if (sr.stat == SUCCESS) {
        SA_INDEX tmp;
        for (tmp = sr.left; tmp <= sr.right; tmp++) { /* '<=' に注意 */
            SA_INDEX index = sa_aryidx2txtidx(ary, tmp);
	    char *pointer = sa_aryidx2txtptr(ary, tmp);
	    SA_STRING str, btag, etag;    
	    char *txt_ptr;

            printf("★テキストファイルの %ld 文字目からマッチ\n", index);
            printf("★先頭二文字表示(1)\n%.*s\n", 2, pointer);
	    str.ptr = pointer;
	    str.len = 2;
            txt_ptr = malloc(3);
	    sa_copy_region(txt_ptr, str);
            printf("★先頭二文字表示(2)\n%s\n", txt_ptr);
            free(txt_ptr);
            txt_ptr = sa_dup_region(str);
            printf("★先頭二文字表示(3)\n%s\n", txt_ptr);
            free(txt_ptr);

            str = sa_seek_context_lines(ary, pointer, 0, 0);
            printf("★一行表示\n%.*s\n", str.len, str.ptr);
            str = sa_seek_context_lines(ary, pointer, 1, 1);
            printf("★前後の一行も表示\n%.*s\n", str.len, str.ptr);
	    btag.ptr = "<DOC>"; btag.len = 5;
            etag.ptr = "</DOC>"); etag.len = 6;
            str = sa_seek_context_region(ary, pointer, btag, etag);
            printf("★DOC タグに囲まれた領域を表示\n%.*s\n", str.len, str.ptr);
        }
    }

    sa_close(ary);
    return 0;
}

正規表現を用いた検索

注意: 正規表現検索周りはまだ作業中のため 今後仕様が著しく変更される可能性があります。

関数

SA_RESULT_LIST *sa_regex(SUFARY * ary, SA_INDEX left, SA_INDEX right, char *keyword, int keyword_length)
正規表現を用いた検索を行います。 検索結果はリスト構造になっています。
SA_RESULT_LIST *sa_ignore_case(SUFARY * ary, SA_INDEX left, SA_INDEX right, char *keyword, int keyword_length)
大文字小文字の違いを無視した検索を行います。 検索結果はリスト構造になっています。
void sa_free_result_list(SA_RESULT_LIST *listp)
検索結果のリストを消します。

エラー処理

考え中...

DocID ファイルによるテキストエリアの取り出し

関数

DID *sa_open_did(char *file_name)
DocID ファイルを開きます。 ファイルを開くのに成功した場合は、 DID 型変数へのポインタを、失敗した場合は NULL を返します。
sa_close_did(DID *did)
DocID ファイルを閉じます。
DID_RESULT sa_didsearch(DID *did, SA_INDEX target)
テキスト位置 target が含まれるテキストエリアの 開始位置 ( start )、 大きさ ( size )、 通し番号 ( no ) 等の情報を取ってきて、 DID_RESULT 型変数に格納します。

// DID_RESULT //

typedef struct {
    SA_INDEX start;
    SA_INDEX size;
    SA_INDEX no;
    SA_STAT stat;
} DID_RESULT;
該当するテキストエリアがなければ、stat に FAIL が、あれば SUCCESS が入ります。

// 例 //

DID_RESULT dr = sa_didsearch(did, 192);
if (dr.stat == SUCCESS)
    printf("no. %ld, start %ld, size %ld\n", dr.no, dr.start, dr.size);
SA_INDEX sa_get_start_position(DID *did, SA_INDEX i)
i 番目のテキストエリアの開始位置位置を得ます。
SA_INDEX sa_get_end_position(DID *did, SA_INDEX i)
i 番目のテキストエリアの終了位置を得ます。
SA_INDEX sa_get_did_size(DID *did)
DocID ファイルで取り出すことのできる テキストエリアの数を得ます。

// 例:全テキストエリアを表示 //

for (i = 0; i > sa_get_did_size(did); i++) {
	SA_INDEX doc_start = sa_get_start_position(did, i);
	SA_INDEX doc_end = sa_get_end_position(did, i);
	printf("-- Text Area No. %ld\n%.*s\n", i, doc_end - doc_start, 
	       sa_txtidx2txtptr(ary, doc_start));
}

サンプルプログラム

// sample-did.c //

#include <stdio.h>
#include <stdlib.h>
#include "sufary.h"

int main(int argc, char *argv[]) 
{
    SUFARY *ary;
    DID *did;
    SUF_RESULT sr;

    ary = sa_open(argv[2], NULL);
    did = sa_open_did(argv[3]);
    if (ary == NULL || did == NULL)
        exit(1);

    printf("★いくつあるかな ... %ld\n", sa_get_did_size(did));

    sr = sa_find(ary, 0, sa_get_array_size(ary) - 1, argv[1], strlen(argv[1]), 0);
    if (sr.stat == SUCCESS) {
        SA_INDEX tmp;
        for (tmp = sr.left; tmp <= sr.right; tmp++) { /* '<=' に注意 */
            SA_INDEX pos = sa_aryidx2txtidx(ary, tmp);
            DID_RESULT dr = sa_didsearch(did, pos);
            if (dr.stat == FAIL)
                continue;
            printf("★ no. %ld, start %ld, size %ld\n",
                   dr.no, dr.start, dr.size);
            printf("★テキストエリア表示(1)\n");
            printf("%.*s\n", dr.size, sa_txtidx2txtptr(ary, dr.start));
            printf("★テキストエリア表示(2)\n");
            printf("%.*s\n", dr.size,
                   sa_txtidx2txtptr(ary, sa_get_start_position(did, dr.no)));
        }
    }

    sa_close_did(did);
    sa_close(ary);
    return 0;
} 

インデックスファイルの作成

array ファイルの作成

DocID ファイルの作成

version 2.1.x からの変更点

version 2.1.x から 3.x へ移行する際に、 マイナーバージョンアップではできないような大幅な仕様変更を行いました。


tatuo-y@is.aist-nara.ac.jp