MeCab ライブラリ

$Id: libmecab.html 65 2007-01-30 00:52:53Z taku-ku $;

C ライブラリ仕様

C ライブラリは以下の関数を提供しています.

mecab_t *mecab_new (int argc, char **argv)
mecab のインスタンスを生成します.
引数には, C 言語の, main 関数で使用される argc, argv スタイルの引数を与えます.
この引数は, mecab コマンドと同じ方法で処理されます.
成功すれば, mecab_t 型のポインタが返ってきます. このポインタを通して解析 を行います. 失敗すれば NULL が返ってきます.
mecab_t *mecab_new2 (const char *arg)
mecab のインスタンスを生成します.
引数には, 一つの文字列として表現したパラメータを与えます.
成功すれば, mecab_t 型のポインタが返ってきます. このポインタを通して解析を行います.
const char *mecab_version()
mecab の version を文字列として取得します.
const char *mecab_strerror (mecab_t* m)
エラーの内容を文字列として取得します. mecab_sparse_tostr 等で, NULL が返ってきた場合に, mecab_strerror を呼ぶことで, エラーの内容を取得できます. mecab_new,mecab_new2 のエラーは, m を NULL と指定してください.
const char *mecab_sparse_tostr (mecab_t *m, const char *str)
解析を行います. 引数には, mecab_new で得られた mecab_t 型のポインタと,
解析したい文を char 型のポインタ文字列として与えます.
成功すれば, 解析後の結果が char 型のポインタとして返り, 失敗すれば, NULL が返ってきます
戻り値のポインタが指すメモリ領域は, 呼び出し側で管理する必要はありませんが,
mecab_sparse_tostr を呼ぶ度に上書きされます.
また, mecab_destroy を呼ぶと解放されます.
const char *mecab_sparse_tostr2 (mecab_t *m, const char *str, size_t len)
mecab_sparse_tostr とほぼ同じですが, len にて, 解析する文の長さを指定できます.
char *mecab_sparse_tostr3 (mecab_t *m, const char *istr,size_t ilen char *ostr, size_t olen)
mecab_sparse_tostr2 に加え, 出力用の バッファ領域 (ostr), 及びその長さ (olen) を指定できます. ostr の領域の管理は, 呼び出し側が行います. 成功すれば, 解析後の結果が char 型のポインタとして返ってきます. これは, ostr と同じになります. もし, 解析結果の長さが olen 以上になった場合は, 解析失敗とみなし, NULL を返します.
const char *mecab_nbest_sparse_tostr (mecab_t *m, size_t N, const char *str)
mecab_sparse_tostr () の N-Best 解出力 version です. N にて解析結果の個 数を指定します. また, N-Best の機能を使う場合は, 必ず mecab_new にて -l 1 オプションを指定する必要があります.
const char *mecab_nbest_sparse_tostr2 (mecab_t *m, size_t N, const char *str, size_t len)
mecab_sparse_tostr2 () の N-Best 解出力 version です. N にて解析結果の個 数を指定します.
char *mecab_nbest_sparse_tostr3 (mecab_t *m, size_t N, const char *str, size_t len, char *ostr, size_t olen)
mecab_sparse_tostr3 () の N-Best 解出力 version です. N にて解析結果の個 数を指定します.
int mecab_nbest_init (mecab_t* m, const char* str);
解析結果を, 確からしいものから順番に取得する場合にこの関数で初期化を行い ます. 解析したい文を str に指定します. 初期化に成功すると 1 を, 失敗する と 0 を返します. 失敗の原因は, mecab_strerror で取得できます.
int mecab_nbest_init2 (mecab_t* m, const char* str, len);
mecab_nbest_init () とほぼ同じですが, len にて文の長さを指定できます.
const char *mecab_nbest_next_tostr (mecab_t* m)
mecab_nbest_init() の後, この関数を順次呼ぶことで, 確からしい解析結果 を, 順番に取得できます. 失敗すると (これ以上の解が存在しない場合) NULL を返します. 失敗の原因は, mecab_strerror で取得できます.
char *mecab_nbest_next_tostr2 (mecab_t *m , char *ostr, size_t olen)
mecab_nbest_tostr() とほぼ同じですが, ostr, olen にて出力用のバッファを 指定できます. 失敗すると (これ以上の解が存在しない場合) NULL を返します. また, 出力バッファが溢れた場合も NULL を返します. 失敗の原因は, mecab_strerror で取得できます.
void mecab_destroy(mecab_t *m)
mecab_t 型のポインタを解放します.

形態素情報を取り出すには,以下の mecab_node_t 構造体と mecab_sparse_tonode 関数を使います

#define MECAB_NOR_NODE  0
#define MECAB_UNK_NODE  1
#define MECAB_BOS_NODE  2
#define MECAB_EOS_NODE  3

struct mecab_node_t
{
  struct mecab_node_t  *prev;  // 一つ前の形態素へのポインタ
  struct mecab_node_t  *next;  // 一つ先の形態素へのポインタ
  
  struct mecab_node_t  *enext; // 同じ位置で終わる形態素へのポインタ
  struct mecab_node_t  *bnext; // 同じ開始位置で始まる形態素へのポインタ

  char  *surface;             // 形態素の文字列情報 
                              // NULL terminateされていません. 文字列として取り出すには
			      // strncpy(buf, node->feature, node->length) とする必要があります
			      
  char  *feature;             // CSV で表記された素性情報
  unsigned int   length;      // 形態素の長さ
  unsigned int   rlength;     // 形態素の長さ(先頭のスペースを含む)
  unsigned int   id;          // 形態素に付与される ユニークID
  unsigned short rcAttr;      // 右文脈 id 
  unsigned short lcAttr;      // 左文脈 id
  unsigned short posid;       // 形態素 ID (未使用)
  unsigned char  char_type;   // 文字種情報
  unsigned char  stat;        // 形態素の種類: 以下のマクロの値
                              // #define MECAB_NOR_NODE  0
                              // #define MECAB_UNK_NODE  1
                              // #define MECAB_BOS_NODE  2
                              // #define MECAB_EOS_NODE  3
  unsigned char  isbest;      // ベスト解の場合 1, それ以外 0

  float          alpha;       // forward backward の foward log 確率
  float          beta;        // forward backward の backward log 確率 
  float          prob;        // 周辺確率
                              // alpha, beta, prob は -l 2 オプションを指定した時に定義されます

  short          wcost;       // 単語生起コスト
  long           cost;        // 累積コスト
};
mecab_node_t *mecab_sparse_tonode (mecab_t *m, const char *str)
解析を行います. 引数には, mecab_new で得られた mecab_t 型のポインタと,
解析したい文を char 型のポインタ文字列として与えます.
成功すれば, 文頭の形態素(mecab_node_t型)へのポインタが返り, 失敗すれば, NULLが返ってきます.
mecab_node_t は双方向リストになっているため next, prev を順にたどる事で 全形態素を列挙することができます.
戻り値のポインタが指すメモリ領域は, 呼び出し側で管理する必要はありませんが,mecab_sparse_tonode を呼ぶ度に上書きされます.
また, mecab_destroy を呼ぶと解放されます.
mecab_node_t *mecab_sparse_tonode2 (mecab_t *m, const char *str, size_t len)
mecab_sparse_tonode とほぼ同じですが, len にて, 解析する文の長さを指定できます.
mecab_node_t *mecab_next_tonode (mecab_t* m)
mecab_next_tostr とほぼ同じですが,文字列ではなく mecab_node_t 型の形態素情報を返します.

C サンプル

example/example.c

#include <mecab.h>
#include <stdio.h>

#define CHECK(eval) if (! eval) { \
    fprintf (stderr, "Exception:%s\n", mecab_strerror (mecab)); \
    mecab_destroy(mecab); \
    return -1; }

int main (int argc, char **argv) 
{
  char input[1024] = "太郎は次郎が持っている本を花子に渡した。";
  mecab_t *mecab;
  mecab_node_t *node;
  const char *result;
  int i;

  mecab = mecab_new (argc, argv);
  CHECK(mecab);

  result = mecab_sparse_tostr(mecab, input);
  CHECK(result)
  printf ("INPUT: %s\n", input);
  printf ("RESULT:\n%s", result);

  result = mecab_nbest_sparse_tostr (mecab, 3, input);
  CHECK(result);
  fprintf (stdout, "NBEST:\n%s", result);

  CHECK(mecab_nbest_init(mecab, input));
  for (i = 0; i < 3; ++i) {
    printf ("%d:\n%s", i, mecab_nbest_next_tostr (mecab));
  }

  node = mecab_sparse_tonode(mecab, input);
  CHECK(node);
  for (; node; node = node->next) {
    fwrite (node->surface, sizeof(char), node->length, stdout);
    printf("\t%s\n", node->feature);
  }

  node = mecab_sparse_tonode(mecab, input);
  CHECK(node);
  for (;  node; node = node->next) {
    printf("%d ", node->id);
    
    if (node->stat == MECAB_BOS_NODE)
      printf("BOS");
    else if (node->stat == MECAB_EOS_NODE)
      printf("EOS");
    else
      fwrite (node->surface, sizeof(char), node->length, stdout);

    printf(" %s %d %d %d %d %d %d %d %d %f %f %f %d\n",
	   node->feature,
	   (int)(node->surface - input),
	   (int)(node->surface - input + node->length),
	   node->rcAttr,
	   node->lcAttr,
	   node->posid,
	   (int)node->char_type,
	   (int)node->stat,
	   (int)node->isbest,
	   node->alpha,
	   node->beta,
	   node->prob,
	   node->cost);
  }

  mecab_destroy(mecab);
   
  return 0;
}

C++ ライブラリ仕様

以下が C++ API です. 基本的に C のインタフェイスと同一ですが,

といった違いがあります.

namespace MeCab
{
  typedef struct mecab_node_t        Node;

  class Tagger
  {
  public:

    virtual const char* parse(const char*, size_t, char*, size_t) = 0;

    virtual const char* parse(const char*, size_t = 0) = 0;
    virtual Node* parseToNode(const char*, size_t = 0) = 0;

    virtual const char* parseNBest(size_t, const char*, size_t = 0) = 0;
    virtual bool  parseNBestInit(const char*, size_t = 0) = 0;
    virtual Node*  nextNode() = 0;
    virtual const char* next() = 0;
    virtual const char* formatNode(Node *) = 0;

    virtual const char* next(char*, size_t) = 0;
    virtual const char* parseNBest(size_t, const char*,
                                   size_t, char *, size_t) = 0;
    virtual const char* formatNode(Node *, char *, size_t) = 0;

    virtual const char* what() = 0;

    virtual ~Tagger() {};

    static const char *version();

    static Tagger* create(int, char**);
    static Tagger* create(const char*);
  };

  /* factory method */
  Tagger *createTagger (int, char**);
  Tagger *createTagger (const char*);
  const char* getTaggerError ();
}

C++ サンプル

#include <iostream>
#include <mecab.h>

#define CHECK(eval) if (! eval) { \
   const char *e = tagger ? tagger->what() : MeCab::getTaggerError(); \
   std::cerr << "Exception:" << e << std::endl; \
   delete tagger; \
   return -1; }

int main (int argc, char **argv) 
{
  char input[1024] = "太郎は次郎が持っている本を花子に渡した。";

  MeCab::Tagger *tagger = MeCab::createTagger (argc, argv);
  CHECK(tagger);

  const char *result = tagger->parse(input);
  CHECK(result);
  std::cout << "INPUT: " << input << std::endl;
  std::cout << "RESULT: " << result << std::endl;

  result = tagger->parseNBest(3, input);
  CHECK(result); 
  std::cout << "NBEST: " << std::endl << result;

  CHECK(tagger->parseNBestInit(input));
  for (int i = 0; i < 3; ++i) {
    std::cout << i << ":" << std::endl << tagger->next();
  } 

  MeCab::Node* node = tagger->parseToNode(input);
  CHECK(node);
  for (; node; node = node->next) {
    std::cout.write(node->surface, node->length);
  }

  node = tagger->parseToNode(input);
  CHECK(node);

  for (; node; node = node->next) {
    std::cout << node->id << ' ';
    if (node->stat == MECAB_BOS_NODE)
      std::cout << "BOS";
    else if (node->stat == MECAB_EOS_NODE)
      std::cout << "EOS";
    else
      std::cout.write (node->surface, node->length);

    std::cout << ' ' << node->feature
	      << ' ' << (int)(node->surface - input)
	      << ' ' << (int)(node->surface - input + node->length)
	      << ' ' << node->rcAttr
	      << ' ' << node->lcAttr
	      << ' ' << node->posid
	      << ' ' << (int)node->char_type
	      << ' ' << (int)node->stat
	      << ' ' << (int)node->isbest
	      << ' ' << node->alpha
	      << ' ' << node->beta
	      << ' ' << node->prob
	      << ' ' << node->cost << std::endl;
  }

  delete tagger;
   
  return 0;
}

コンパイル方法

マルチスレッドについて

MeCab は,マルチスレッド環境で使用することが可能です. 1つのスレッドに 1インスタンス(mecab_t *)を割り当てる場合はスレッドセーフです. さらに, 同じ辞書を使い続ける限り,辞書を保持しているリソースは 再利用されるため, 複数のインスタンスを作成しても多くのメモリを使用することはありません.

一つのインスタンスを複数のスレッドから使う場合は適当に排他制御する必要があります. ただし, パフォーマンスが悪いのでお勧めできません.


$Id: libmecab.html 65 2007-01-30 00:52:53Z taku-ku $;