[前へ] [次へ] [目次]

## 検索

CD-ROM 書籍において、検索は非常に重要な機能です。 EB ライブラリでは、次のような検索メソッドが利用できます。

- 前方一致検索 (word search)
- 後方一致検索 (end-word search)
- 完全一致検索 (exact-word search)
- 条件検索 (keyword search)
- クロス検索 (cross search)
- 複合検索 (multi search)

ただし、すべての CD-ROM 書籍、すべての副本で、ここに挙げたすべての 検索メソッドが利用可能なわけではありません。 副本の中には、いずれの検索メソッドも提供しないものも存在します。

EB ライブラリでは、検索を行うことができるのは、選択中の副本に対して だけです。

この章では、それぞれの検索メソッドの簡単な説明と、EB ライブラリでの 扱い方について説明します。

### 前方一致、後方一致、完全一致検索

前方一致、後方一致、完全一致検索は、いずれも一個の入力語に一致する エントリを探し出す検索メソッドです。

前方一致検索は、入力語と先頭部分が一致するエントリを検索します。 たとえば、「江戸」という語は、「江戸」「江戸時代」「江戸っ子」といった エントリに一致します。

後方一致検索は、入力語と末尾が一致するエントリを検索します。 たとえば、`bye' という語は、`bye'、`good bye'、`bye bye' といった エントリに一致します。

完全一致検索は、一個の検索語と完全に一致するエントリだけを検索します。

以下は、前方一致検索のプログラムの例です。 選択中の副本の中から、先頭が `librar` で始まるエントリを探して います。

>     /* book が EB_Book のオブジェクトで、すでに
>      * 書籍に結び付けられ、副本を選択中だと仮定しています。*/
>     #define MAX_HITS 50
>     EB_Hit hits[MAX_HITS];
>     int hit_count;

>     if (eb_search_word(&book, "librar") != EB_SUCCESS) {
>         printf("eb_search_word() failed\n");
>         return;
>     }
>     if (eb_hit_list(&book, MAX_HITS, hits, &hit_count)
>         != EB_SUCCESS) {
>         printf("eb_hit_list() failed\n");
>         return;
>     }

`eb_search_word()` は前方一致検索をリクエストする関数です。 この例では、`librar` という検索文字列を与えています。 ただし、この関数は一致したエントリを返すことはしません。

一致したエントリの取得は、続く `eb_hit_list()` 関数を 呼び出した際に行われます。 `eb_hit_list()` は一致したエントリの一覧を配列 `hits[]` の指す領域に書き込み、見つかった一致エントリの個数 を `&hit_count` の指す領域に書き込みます。 この例では、`eb_hit_list()` は最大で `MAX_HITS` (= 50) 個 のエントリを探します。 (つまり、50 個見つかったら検索を止めます。)

もし、選択中の副本が英々辞典だとすると、少なくとも `library` と `librarian` という 2 つのエントリに関する情報が得られる でしょう。 このとき、配列 `hits[]` は次のようになっています。 (ただし、`library` と `librarian` エントリの 順序は、下の絵とは異なっているかも知れません。)

>     ┌───────────┬───────────┬─
>     │　ｌｉｂｒａｒｉａｎ　│　　ｌｉｂｒａｒｙ　　│
>     └───────────┴───────────┴─
>     　　　ｈｉｔｓ［０］　　　　　ｈｉｔｓ［１］

`hits[]` の中身については、本章の後ろの節でもう少し詳しく 説明します。

ここまでは前方一致検索を例にとりましたが、後方一致の場合は `eb_search_word()` の代わりに `eb_search_endword()` を呼ぶようにします。 他はすべて同じです。

>     if (eb_search_endword(&book, "nalization") != EB_SUCCESS) {
>         printf("eb_search_endword() failed\n");
>         return;
>     }

完全一致の場合も同様です。 `eb_search_exactword()` を呼ぶようにする以外は、すべて同じ です。

>     if (eb_search_exactword(&book, "library") != EB_SUCCESS) {
>         printf("eb_search_exactword() failed\n");
>         return;
>     }

### 条件検索

条件検索は、複数個の入力語にすべて一致するエントリを検索します。 たとえば、英々辞典の条件検索では、入力語をすべて含んだ例文を検索する ようになっているかも知れません。

以下は、条件検索で `make`, `with` という語の双方と 一致するエントリを、選択中の副本の中から探し出すプログラムの断片です。

>     /* book が EB_Book のオブジェクトで、すでに
>      * 書籍に結び付けられ、副本を選択中だと仮定しています。*/
>     static const char *keywords[3] = {"make", "with", NULL};

>     if (eb_search_word(&book, keywords) != EB_SUCCESS) {
>         printf("eb_search_word() failed\n");
>         return;
>     }

条件検索を行う関数は、`eb_search_keyword()` です。 前方一致、後方一致、完全一致検索の関数と基本的に扱い方は一緒ですが、 複数の入力語を受け付けるようになっています。 関数には、入力語の文字列 (へのポインタ) を配列にしたものを渡します。 配列の最後には `NULL` を置き、配列の終端を明示する必要が ある点に注意して下さい。

前方一致、後方一致、完全一致検索と同様に、`eb_search_keyword()` も検索のリクエストを行うだけで、一致したエントリの取得は行いません。 エントリの取得には、やはり同様に `eb_hit_list()` 関数を 使います。

>     EB_Hit hits[MAX_HITS];
>     int hit_count;

>     if (eb_hit_list(&book, MAX_HITS, hits, &hit_count)
>         != EB_SUCCESS) {
>         printf("eb_hit_list() failed\n");
>         return;
>     }

### クロス検索

クロス検索は、条件検索の亜種とも言うべき検索メソッドです。 EPWING や電子ブックをみても、どういうルールで使い分けがなされているのか 分からない程、両者は実によく似ています。

EB ライブラリでクロス検索を行う関数は `eb_search_cross()` ですが、使い方は条件検索の関数 `eb_search_keyword()` と まったく同じです。 使い方の詳細は、「条件検索」 をご覧下さい。

### 複合検索

複合検索は、条件検索と同じく、複数個の入力語にすべて一致するエントリを 検索しますが、個々の入力語にあらかじめ題目が付けられています。

また、前方一致、後方一致、完全一致、条件検索はすべて、各副本につき 一種類しかありませんが、複合検索だけは一つの副本の中で複数の種類が用意 されていることがあります。 たとえば、ある世界人名事典には、次のように人名検索用と頻出用語の検索用 の 2 種類の複合検索が用意されているかも知れません。

>     (複合検索その 1: 人名を検索する)
>         入力語 0: 国・地域
>         入力語 1: 時代
>         入力語 2: 性別
>         入力語 3: キーワード
>         入力語 4: キーワード

>     (複合検索その 2: 頻出用語を検索する)
>         入力語 0: 用語
>         入力語 1: キーワード
>         入力語 2: キーワード

この例のように、個々の複合検索は、入力語の題目だけでなく、入力語の数も まちまちです。 また、検索する際はすべての入力語を埋める必要はなく、少なくとも一個の 入力語が空でなければ、検索は成功します。

副本内の複合検索は、種類毎に 複合検索コード (multi search code) によって識別されます。 関数 `eb_multi_search_list()` を使うと、選択中の副本で利用可能 な複合検索の一覧が得られます。

>     /* book が EB_Book のオブジェクトで、すでに
>      * 書籍に結び付けられ、副本を選択中だと仮定しています。*/
>     EB_Multi_Search_Code multi_codes[EB_MAX_MULTI_SEARCHES];
>     int multi_count;

>     if (eb_multi_search_list(&book, multi_codes, &multi_count)
>         != EB_SUCCESS) {
>         printf("eb_multi_search_list() failed\n");
>         return;
>     }

この複合検索コードは、複合検索のための関数で必要となります。 たとえば、`eb_multi_title()` は、指定した複合検索の題名 (例:「人名検索」「頻出用語検索」) を取得する関数ですが、このときの 複合検索の指定には、複合検索コードを用います。 以下の例では、一覧の先頭に載っている複合検索 (`multi_codes[0]`) を指定しています。

>     char title[EB_MAX_MULTI_TITLE_LENGTH + 1];

>     if (eb_multi_title(&book, multi_codes[0], title)
>         != EB_SUCCESS) {
>         printf("eb_multi_title() failed\n");
>         return;
>     }

さらに関数によっては、複合検索コードに加えて、何番目の入力語かも指定 してやる必要があります。 たとえば、特定の入力語の題目を得る関数 `eb_multi_entry_label()` が、これに該当します。 0 番目の入力語 (つまり先頭の入力語) の題目を取得するには、次のように します。

>     char label[EB_MAX_MULTI_LABEL_LENGTH + 1];

>     if (eb_multi_entry_label(&book, multi_code[0], 0, label)
>         != EB_SUCCESS) {
>         printf("eb_multi_entry_label() failed\n");
>         return;
>     }

複合検索を行う関数は、`eb_search_multi()` です。 使い方は条件検索とほぼ同じで、入力語の文字列を配列にしたものを引数 として渡し、配列の最後には `NULL` を置いて下さい。 埋められていない入力語のところには、空文字列を置きます。

`eb_search_multi()` も検索のリクエストを行うだけで、一致した エントリの取得は行いません。 取得するには `eb_hit_list()` を使います。

>     EB_Hit hits[MAX_HITS];
>     int hit_count;

>     if (eb_hit_list(&book, MAX_HITS, hits, &hit_count)
>         != EB_SUCCESS) {
>         fprintf(stderr, "an error occurs.\n");
>         return;
>     }

なお、複合検索の入力語によっては 候補一覧 (candidates) があらじめ用意されていることがあります。 これは、入力語として有効な語をあらかじめ列挙しておき、 アプリケーションプログラムのユーザに選択させる仕組みです。 候補一覧については、この章ではなく「テキストデータ」の章で説明します (「複合検索の候補一覧」 を参照のこと)。

### 一致エントリの情報

`eb_hit_list()` は、リクエストされた検索 (前方一致、後方一致、 完全一致、条件、複合) に一致したエントリの情報と見つかったエントリの 個数を、それぞれ `EB_Hit` 型の配列領域および `int` 型の 領域に書き込みます。

>     /* book が EB_Book のオブジェクトで、すでに書籍に結び付け
>      * られ、副本を選択中だと仮定しています。*/
>     EB_Hit hits[MAX_HITS];
>     int hit_count;

>     if (eb_hit_list(&book, MAX_HITS, hits, &hit_count)
>         != EB_SUCCESS) {
>         fprintf(stderr, "an error occurs.\n");
>         return;
>     }

`EB_Hit` 配列の個々の要素には、一致したエントリの 見出し (heading) と 本文 (text) の開始位置が 書き込まれています。

>     　　　　　　　　　　　　　見出し
>     　　　　　　　　　　　　┌────────────┐
>     　ＥＢ＿Ｈｉｔ　　　┏━┿ｌｉｂｒａｒｉａｎ　ｎ．│
>     ┌───────┐　┃　└────────────┘
>     │ｈｅａｄｉｎｇ┿━┛　　本文
>     │　　　　　　　│　　　┌────────────────────┐
>     │　　　ｔｅｘｔ┿━━━┿ｌｉｂｒａｒｉａｎ　　　　　　　　　　　│
>     └───────┘　　　│ｎ．（１）Ａ　ｐｅｒｓｏｎ　ｗｈｏ　ｉｓ│
>     　　　　　　　　　　　　│ａ　ｓｐｅｃｉａｌｉｓｔ　ｉｎ　　　　　│
>     　　　　　　　　　　　　│ｌｉｂｒａｒｙ　ｗｏｒｋ．（２）．．．　│
>     　　　　　　　　　　　　└────────────────────┘

見出しと本文についてのより詳しい解説と取得方法については、 「テキストデータ」 を参照のこと。

### 残っているエントリの取得

前に述べたように、`eb_hit_list()` を呼び出すときは、一致する エントリを最大で何個まで探すのかを引数で指定します。 また、`eb_hit_list()` は処理が成功すると、実際に見つかった エントリの数をアプリケーションプログラムに教えます。

>     error_code = eb_hit_list(&book, MAX_HITS, hits, &hit_count);
>     if (error_code == EB_SUCCESS)
>         printf("%d entries found\n", hit_count);

指定した最大個数よりも多くの一致エントリが副本に存在している場合は、 `eb_hit_list()` を繰り返し呼び出すことで、残りのエントリを 取得することができます。

>     for (;;) {
>         if (eb_hit_list(&book, MAX_HITS, hits, &hit_count)
>             != EB_SUCCESS) {
>             fprintf(stderr, "an error occurs.\n");
>             return;
>         }
>         if (hit_count == 0)
>             break;
>         /* 取得した一致エントリの処理 */
>     }

一致エントリがもう残っていなければ、`eb_hit_list()` は `&hit_count` の指す領域に 0 を書き込んで、 `EB_SUCCESS` を返します。

ただし、途中で `eb_hit_list()` が失敗すると (`EB_SUCCESS` 以外の値を返すと)、検索リクエストに関する 状態記録はリセットされるため、一致エントリの取得をそれ以上続けることは できません。

### 重複エントリの削除

`eb_hit_list()` を用いて一致したエントリを取得すると、中身が 実質的に変わらないエントリが複数含まれていることがあります。 EB ライブラリは、こうした重複エントリの削除は行いません。 必要なら、アプリケーション側で行うことになります。

重複を完璧に取り除くなら、以下のすべての条件に一致するエントリを 重複エントリとみなし、二度目以降に出現したエントリを削除します。

- エントリの指す本文の位置が同じ
- エントリの指す見出しの文字列 (位置ではなく文字列そのもの) が同じ

(見出し文字列の取得方法については、 「テキストデータ」 を参照のこと。)

重複は、直前のエントリに対してのみ起こるとは限りません。 たとえば、`eb_hit_list()` で一致エントリが 50 個得られた場合、 最後の 50 個目は前方の 49 個と重複検査を行う必要があります。 したがって、全体ではエントリ同士の比較を 1 + 2 + ... + 49 = 1225 回 行うことになります。

書籍によっては重複エントリが取りきれない可能性もありますが、もう少し 簡単な方法もいくつかあります。 処理を簡単にする第一の方法は、重複エントリの判定条件を次のように変える ことです。

- エントリの指す本文の位置が同じ
- エントリの指す見出しの文字列の位置が同じ

さらに処理を簡単にするには、直前の 1個のエントリに対してだけ重複検査を 行うという方法もあります。 これなら、50 個の一致エントリに対して、比較は 49 回で済みます。 ただしこの方法は、書籍によってはまったく効果がありません。

### サンプルプログラム

>     /*                                                            -*- C -*-
>      * Copyright (c) 1999-2006  Motoyuki Kasahara
>      *
>      * Redistribution and use in source and binary forms, with or without
>      * modification, are permitted provided that the following conditions
>      * are met:
>      * 1. Redistributions of source code must retain the above copyright
>      *    notice, this list of conditions and the following disclaimer.
>      * 2. Redistributions in binary form must reproduce the above copyright
>      *    notice, this list of conditions and the following disclaimer in the
>      *    documentation and/or other materials provided with the distribution.
>      * 3. Neither the name of the project nor the names of its contributors
>      *    may be used to endorse or promote products derived from this software
>      *    without specific prior written permission.
>      *
>      * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
>      * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
>      * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
>      * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
>      * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
>      * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
>      * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
>      * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
>      * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
>      * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
>      * SUCH DAMAGE.
>      */

>     /*
>      * 使用方法:
>      *     word <book-path> <subbook-index> <word>
>      * 例:
>      *     word /cdrom 0 apple
>      * 説明:
>      *     <book-path> で指定した CD-ROM 書籍の特定の副本の中から <word>
>      *     という単語を完全一致検索で探し、ヒットしたすべてのエントリの
>      *     見出しを表示します。
>      *
>      *     <subbook-index> には、検索対象の副本のインデックスを指定しま
>      *     す。インデックスは、書籍の最初の副本から順に 0、1、2 ... に
>      *     なります。
>      */
>     #include <stdio.h>
>     #include <stdlib.h>

>     #include <eb/eb.h>
>     #include <eb/error.h>
>     #include <eb/text.h>

>     #define MAX_HITS 50
>     #define MAXLEN_HEADING 127

>     int
>     main(int argc, char *argv[])
>     {
>         EB_Error_Code error_code;
>         EB_Book book;
>         EB_Subbook_Code subbook_list[EB_MAX_SUBBOOKS];
>         EB_Hit hits[MAX_HITS];
>         char heading[MAXLEN_HEADING + 1];
>         int subbook_count;
>         int subbook_index;
>         int hit_count;
>         ssize_t heading_length;
>         int i;

>         /* コマンド行引数をチェック。*/
>         if (argc != 4) {
>             fprintf(stderr, "Usage: %s book-path subbook-index word\n",
>                 argv[0]);
>             exit(1);
>         }

>         /* EB ライブラリと `book' を初期化。*/
>         eb_initialize_library();
>         eb_initialize_book(&book);

>         /* 書籍を `book' に結び付ける。*/
>         error_code = eb_bind(&book, argv[1]);
>         if (error_code != EB_SUCCESS) {
>             fprintf(stderr, "%s: failed to bind the book, %s: %s\n",
>                 argv[0], eb_error_message(error_code), argv[1]);
>             goto die;
>         }

>         /* 副本の一覧を取得。*/
>         error_code = eb_subbook_list(&book, subbook_list, &subbook_count);
>         if (error_code != EB_SUCCESS) {
>             fprintf(stderr, "%s: failed to get the subbbook list, %s\n",
>                 argv[0], eb_error_message(error_code));
>             goto die;
>         }

>         /* 副本のインデックスを取得。*/
>         subbook_index = atoi(argv[2]);

>         /*「現在の副本 (current subbook)」を設定。*/
>         error_code = eb_set_subbook(&book, subbook_list[subbook_index]);
>         if (error_code != EB_SUCCESS) {
>             fprintf(stderr, "%s: failed to set the current subbook, %s\n",
>                 argv[0], eb_error_message(error_code));
>             goto die;
>         }

>         /* 単語検索のリクエストを送出。*/
>         error_code = eb_search_exactword(&book, argv[3]);
>         if (error_code != EB_SUCCESS) {
>             fprintf(stderr, "%s: failed to search for the word, %s: %s\n",
>                 argv[0], eb_error_message(error_code), argv[3]);
>             goto die;
>         }

>         for (;;) {
>             /* 残っているヒットエントリを取得。*/
>             error_code = eb_hit_list(&book, MAX_HITS, hits, &hit_count);
>             if (error_code != EB_SUCCESS) {
>                 fprintf(stderr, "%s: failed to get hit entries, %s\n",
>                     argv[0], eb_error_message(error_code));
>                 goto die;
>             }
>             if (hit_count == 0)
>                 break;

>             for (i = 0; i < hit_count; i++) {
>                 /* 見出しの位置へ移動。*/
>                 error_code = eb_seek_text(&book, &(hits[i].heading));
>                 if (error_code != EB_SUCCESS) {
>                     fprintf(stderr, "%s: failed to seek the subbook, %s\n",
>                         argv[0], eb_error_message(error_code));
>                     goto die;
>                 }

>                 /* 見出しを取得して表示。*/
>                 error_code = eb_read_heading(&book, NULL, NULL, NULL,
>                     MAXLEN_HEADING, heading, &heading_length);
>                 if (error_code != EB_SUCCESS) {
>                     fprintf(stderr, "%s: failed to read the subbook, %s\n",
>                         argv[0], eb_error_message(error_code));
>                     goto die;
>                 }
>                 printf("%s\n", heading);
>             }
>         }

>         /* 書籍と EB ライブラリの利用を終了。*/
>         eb_finalize_book(&book);
>         eb_finalize_library();
>         exit(0);

>         /* エラー発生で終了するときの処理。*/
>       die:
>         eb_finalize_book(&book);
>         eb_finalize_library();
>         exit(1);
>     }

### データ型の詳細

この節で説明しているデータ型を使うには、次のようにヘッダファイルを 読み込んで下さい。

>     #include <eb/eb.h>

#### `EB_Hit` 型

`EB_Hit` は、検索に一致したエントリの情報を格納するための データ型です。 内部構造は、次のように定義されています。

>     typedef struct EB_Hit_Struct EB_Hit;

>     struct EB_Hit_Struct {
>         EB_Position heading;  /* 見出しの位置 */
>         EB_Position text;     /* 本文の位置   */
>     };

アプリケーションプログラムは、直接 `EB_Hit` オブジェクトの メンバを参照したり、セットしたりしても構いません。

#### `EB_Position` 型

データ型 `EB_Position` は、副本のデータの位置を表します。 内部構造は、次のように定義されています。

>     typedef struct EB_Position_Struct EB_Position;

>     struct EB_Position_Struct {
>         int page;     /* ページ番号 */
>         int offset;   /* ページ内のオフセット */
>     };

ページ番号は 1 から始まり、ページ内のオフセットは 0 〜 2047 の範囲と なります。 ただし、アプリケーションプログラムを作成する上で、このことを覚えておく 必要はありません。

アプリケーションプログラムは、直接 `EB_Position` オブジェクト のメンバを参照したり、セットしたりしても構いません。

#### `EB_Multi_Search_Code` 型

データ型 `EB_Multi_Search_Code` は複合検索コードを表します。 副本に用意されている複合検索は、それぞれ一意の複合検索コードを 持っています。 この型は符合付き整数型の別名として定義されていますので、2 つのコードを 2 項演算子 `==` と `!=` で一致比較することが できます。

また、不正な複合検索コード値を表す `EB_MULTI_INVALID` という 特別な副本コードが定義されています。 利用可能な複合検索に対して、この複合検索コードが割り当てられることは ありません。

### 関数の詳細

この節で説明している関数を使うには、次のようにヘッダファイルを読み込んで 下さい。

>     #include <eb/eb.h>

#### `int eb_have_word_search (EB_Book *book)`

#### `int eb_have_endword_search (EB_Book *book)`

#### `int eb_have_exactword_search (EB_Book *book)`

関数 `eb_have_word_search()` は、book が選択中の 副本で前方一致検索メソッドが利用可能どうかを調べます。 同様に `eb_have_endword_search()` は後方一致検索メソッドに ついて、`eb_have_exactword_search()` は完全一致検索メソッドに ついて利用可能どうかを調べます。

利用可能なら 1 を返します。 メソッドを持っていないか、そもそも副本が選択されていない場合は 0 を 返します。

#### `int eb_have_keyword_search (EB_Book *book)`

関数 `eb_have_keyword_search()` は、book が選択中の 副本で条件検索メソッドが利用可能どうかを調べます。

利用可能なら 1 を返します。 メソッドを持っていないか、そもそも副本が選択されていない場合は 0 を 返します。

#### `int eb_have_multi_search (EB_Book *book)`

関数 `eb_have_multi_search()` は、book が選択中の 副本で複合検索メソッドが利用可能どうかを調べます。

最低 1 種類でも利用可能なら 1 を返します。 メソッドを持っていないか、そもそも副本が選択されていない場合は 0 を 返します。

#### `EB_Error_Code eb_multi_search_list (EB_Book *book, EB_Multi_Search_Code *multi_list, int *multi_count)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索を調べ、複合検索コードの一覧を `EB_Multi_Search_Code` 型の配列にして、multi_list の指す領域に書き込みます。 配列は、最大で `EB_MAX_MULTI_SEARCHES` 個の要素を持ちます。 加えて、複合検索の種類数を multi_count の指す領域に書き込みます。

成功すると、関数は `EB_SUCCESS` を返します。 失敗すると、subbook_count の指す領域に 0 を書き込み、原因を示す エラーコードを返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。

#### `EB_Error_Code eb_multi_entry_count (EB_Book *book, EB_Multi_Search_Code multi_id, int *entry_count)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索 multi_id について調べ、入力語の 個数を entry_count の指す領域に書き込みます。

成功すると、関数は `EB_SUCCESS` を返します。 このとき書き込まれる入力語の個数は、1 以上 `EB_MAX_MULTI_ENTRIES` 以下になります。 失敗すると、entry_count の指す領域には 0 を書き込み、原因を示す エラーコードを返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。

#### `EB_Error_Code eb_multi_title (EB_Book *book, EB_Multi_Search_Code multi_id, char *title)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索 multi_id の題名を title の指す領域に書き込みます。 題目は最長で `EB_MAX_MULTI_TITLE_LENGTH` バイトになります。 この長さに、ナル文字は含みません。

書籍の文字コード (「[CD-ROM 書籍と `EB_Book` オブジェクト] データ型の詳細」 を参照のこと) が `EB_CHARCODE_ISO8859_1` なら、題目を表す文字列は ISO 8859-1 になり、それ以外の文字コードなら日本語 EUC になります。

書籍によっては、複合検索は用意していても、複合検索の題名データを持って いないことがあります。 その場合、EB ライブラリが代わりに付けた題名が title に 書き込まれます。

書籍の文字コードが `EB_CHARCODE_ISO8859_1` なら、 EB ライブラリが付ける題名は、"Multi Search 1", "Multi Search 2", ... になります。 それ以外の文字コードであれば、題名は日本語 EUC で書かれた「複合検索 1」 「複合検索 2」... という文字列になります。

成功すると、関数は `EB_SUCCESS` を返します。 失敗すると、label の指す領域には空文字列を書き込み、原因を示す エラーコードを返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。

#### `EB_Error_Code eb_multi_entry_label (EB_Book *book, EB_Multi_Search_Code multi_id, int entry_index, char *label)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索 multi_id について調べ、 entry_index 番目の検索語の題目を label の指す領域に 書き込みます。 entry_index は、先頭の検索語を 0 番目と数えます。 題目は最長で `EB_MAX_MULTI_LABEL_LENGTH` バイトになります。 この長さに、ナル文字は含みません。

書籍の文字コード (「[CD-ROM 書籍と `EB_Book` オブジェクト] データ型の詳細」 を参照のこと) が `EB_CHARCODE_ISO8859_1` なら、題目を表す文字列は ISO 8859-1 になり、それ以外の文字コードなら日本語 EUC になります。

成功すると、関数は `EB_SUCCESS` を返します。 失敗すると、label の指す領域には空文字列を書き込み、原因を示す エラーコードを返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。

#### `int eb_multi_entry_have_candidates (EB_Book *book, EB_Multi_Search_Code multi_id, int entry_index)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索 multi_id について調べ、 entry_index 番目の検索語が候補一覧を持っているかどうか調べます。 entry_index は、先頭の検索語を 0 番目と数えます。

持っていれば 1 を返します。 持っていないか、そもそも副本が選択されていない場合、あるいは multi_id, や entry_index が不正な値だった場合は 0 を返します。

#### `EB_Error_Code eb_multi_entry_candidates (EB_Book *book, EB_Multi_Search_Code multi_id, int entry_index, EB_Position *position)`

関数 `eb_multi_search_list()` は、book が選択中の 副本に用意されている複合検索 multi_id について調べ、 entry_index 番目の検索語の候補一覧の位置を position の指す領域に書き込みます。 先頭の検索語が 0 番目になります。

成功すると、関数は `EB_SUCCESS` を返します。 失敗すると、positin の指す領域には `eb_seek_text()` が必ず失敗する位置情報を書き込み、原因を示すエラーコードを返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。

#### `EB_Error_Code eb_search_word (EB_Book *book, const char *input_word)`

#### `EB_Error_Code eb_search_endword (EB_Book *book, const char *input_word)`

#### `EB_Error_Code eb_search_exactword (EB_Book *book, const char *input_word)`

関数 `eb_search_word()` は、book が選択中の副本に 対する前方一致検索をリクエストします。 同様に `eb_search_endword()` は後方一致検索を、 `eb_search_exactword()` は完全一致検索をリクエストします。

検索する語は、引数 input_word で指定します。 ただし、これらの関数は検索をリクエストするだけで、一致したエントリの 情報を返すことはしません。 一致したエントリの取得には `eb_hit_list()` を使います。 関数は、成功すると `EB_SUCCESS` を返します。 失敗すると、原因を示すエラーコードを返します。 失敗すると、関数を呼び出す前にリクエストしていた検索の状態記録はリセット されますので、その状態のまま `eb_hit_list()` を呼び出しても、 やはり失敗に終わります。

書籍の文字コード (「[CD-ROM 書籍と `EB_Book` オブジェクト] データ型の詳細」 を参照のこと) が `EB_CHARCODE_ISO8859_1` なら、関数に渡す検索語は ISO 8859-1 で書かれていなければなりません。 それ以外の文字コードの場合は、日本語 EUC で書かれていなければなりません。 不正な文字番号を含んでいた場合、関数は `EB_ERR_BAD_WORD` を 返します。

加えて、検索語は 1 バイト以上、`EB_MAX_WORD_LENGTH` (= 255) バイト以下でなければなりません。 この長さに、ナル文字は含みません。 長すぎる場合は、`EB_ERR_TOO_LONG_WORD` を、 長さが 0 (空文字列) の場合は `EB_ERR_EMPTY_WORD` を返します。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。 なお、一致するエントリが最低 1 個あるかどうかは、戻り値には影響しません。

#### `EB_Error_Code eb_search_keyword (EB_Book *book, const char * const input_words[])`

#### `EB_Error_Code eb_search_cross (EB_Book *book, const char * const input_words[])`

#### `EB_Error_Code eb_search_multi (EB_Book *book, EB_Multi_Search_Code multi_id, const char * const input_words[])`

関数 `eb_search_keyword()` は、book が選択中の 副本に対する条件検索をリクエストします。 同様に `eb_search_cross()` はクロス検索を、 `eb_search_multi()` は複合検索をそれぞれリクエストします。

検索する語は、引数 input_words で指定します。 条件検索と複合検索はいずれも複数個の検索語を受け付けますので、検索語を 配列にして渡します。 このとき、配列の末尾の要素には `NULL` を置き、配列の終端を 明示します。

いずれの関数も検索をリクエストするだけで、一致したエントリの情報を 返すことはしません。 一致したエントリの取得には `eb_hit_list()` を使います。 関数は、成功すると `EB_SUCCESS` を返します。 失敗すると、原因を示すエラーコードを返します。 失敗すると、関数を呼び出す前にリクエストしていた検索の状態記録はリセット されますので、その状態のまま `eb_hit_list()` を呼び出しても、 やはり失敗に終わります。

書籍の文字コード (「[CD-ROM 書籍と `EB_Book` オブジェクト] データ型の詳細」 を参照のこと) が `EB_CHARCODE_ISO8859_1` なら、関数に渡す検索語は ISO 8859-1 で書かれていなければなりません。 それ以外の文字コードの場合は、日本語 EUC で書かれていなければなりません。 不正な文字番号を含んでいた場合、関数は `EB_ERR_BAD_WORD` を 返します。

加えて、個々の検索語は `EB_MAX_WORD_LENGTH` (= 255) バイト以下 でなければなりません。 この長さに、ナル文字は含みません。 長すぎる場合は、`EB_ERR_TOO_LONG_WORD` を返します。 長さが 0 バイトの検索語は無視されますが、少なくとも 1 個の検索語は長さ が 1 以上ないといけません。 長さが 1 以上の検索語が 1 つもないときは、`EB_ERR_NO_WORD` を 返します。

末尾の NULL を除いた配列の要素数は、条件検索では `EB_MAX_KEYWORDS` 以下、クロス検索では `EB_MAX_CROSS_ENTRIES` 以下、 複合検索では `EB_MAX_MULTI_ENTRIES` 以下でなくては なりません。 個数が多すぎると `EB_ERRO_TOO_MANY_WORDS` を返します。 空文字列の要素を差し引いた個数ではなく、単純に渡された要素数が上限を 超えているとエラーになりますので、注意が必要です。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。 なお、一致するエントリが最低 1 個あるかどうかは、戻り値には影響しません。

#### `EB_Error_Code eb_hit_list (EB_Book *book, int max_hit_count, EB_Hit *hit_list, int *hit_count)`

関数 `eb_hit_list()` は、あらかじめ以下のいずれかの関数で リクエストされた検索を実行し、一致したエントリを取得します。

- `eb_search_word()` (前方一致検索)
- `eb_search_endword()` (後方一致検索)
- `eb_search_exactword()` (完全一致検索)
- `eb_search_keyword()` (条件検索)
- `eb_search_cross()` (クロス検索)
- `eb_search_multi()` (複合検索)

したがって、この関数を呼ぶ前に、上記のいずれかの関数の呼び出しに成功して いなくてはなりません。

`eb_hit_list()` は最大で max_hit_count 個の 一致エントリを hit_list に書き込みます。 そして、書き込んだ一致エントリの数を hit_count が指す領域に 書き込みます。 それ以上の個数の一致エントリが存在する場合、残ったエントリの情報は、 この関数を繰り返し呼び出すことで得ることができます。

ただし、以下に挙げた関数を呼び出すと、リクエストした検索に関する状態記録 がリセットされますので、一致したエントリの取得は継続できなくなります。

- `eb_set_subbook()`
- `eb_unset_subbook()`
- `eb_load_all_subbooks()`
- `eb_bind()`
- `eb_finalize_book()`
- `eb_search_word()`
- `eb_search_endword()`
- `eb_search_exactword()`
- `eb_search_keyword()`
- `eb_search_cross()`
- `eb_search_multi()`

繰り返し呼んだ場合も、一致したエントリの情報はその都度 hit_list の先頭から書き込み、hit_count が指す領域に書き込む値も、その回 の `eb_hit_list()` の呼び出しで書き込んだ一致エントリの数に なります。

成功すると、この関数は `EB_SUCCESS` を返します。 たとえ一致したエントリがなくても、処理が正常に終了すれば、関数は `EB_SUCCESS` を返します。

失敗すると、hit_count が指す領域に 0 を書き込み、原因を示す エラーコードを返します。 この場合、リクエストしていた検索の状態記録はリセットされますので、 これ以上 `eb_hit_list()` を呼んで、残った一致エントリを取得 することはできなくなります。

あらかじめ、book はいずれかの副本を選択していなくてはなりません。 選択していない場合は、`EB_ERR_NO_CUR_SUB` を返します。 また、先に挙げた検索のリクエストが成功していない状態でこの関数を呼ぶと、 `EB_ERR_NO_PREV_SEARCH` を返します。

[前へ] [次へ] [目次]