ロシア語形態素解析器 Lemmatizer ライブラリ(Лемматизатор европейских языков)を利用した試験プログラムを書いてみた。Lemmatizer はロシア単語の文法構造と見出し語を解析する。このライブラリは C/C++ のアプリケーションから利用できる。UTF-8 テキストを解析できる点で,多国語混在テクスト中のロシア語解析にも応用可能である。このパッケージは先日紹介したものを少し拡張したもののようである。私は FreeBSD で試験したが,Linux,Mac OS X でも動くと思う。Lemmatizer の各ライブラリは静的ライブラリなので,アプリのプログラム・サイズが大きくなってしまうところが残念である。
【インストール】
インストールには CMake が必要である。FreeBSD なら
# cd /usr/ports/devel/cmake && make install clean
で導入可能である。次に Lemmatizer の次の三つのライブラリ・アーカイブをダウンロードページから取得して展開する:libMAFSA-0.2.tar.gz, libturglem-0.2.tar.gz, turglem-russian-0.2.tar.gz。オペレーションは以下のとおり。ただし,turglem-russian-0.2 の make は辞書生成のため,かなりの時間と 100MB 以上のメモリを要するので注意。
% cd libMAFSA-0.2 % cmake . % make % sudo make install % cd ../libturglem-0.2 % cmake . % make % sudo make install % cd ../turglem-russian-0.2 % cmake . % make % sudo make install
【試験プログラム】
Lemmatizer 利用アプリケーション・プログラムの流れは,tl::lemmatizer クラスを生成し,辞書・文法ルールをロードし,解析したい語に対して lemmatize<russian_utf8_adapter> を呼び出す。UTF-8 文字列もそのまま char* に入れればよい(UTF-16 にした wchar_t* などを期待しない)ので面倒がない。解析結果は tl::lem_result クラスに格納されるので,必要な情報をこのクラスから取り出して活用する。サンプルプログラムを参考に私が作成したテストプログラムを,以下に示す。テキストファイルを読込んで,単語を分割し,Lemmatizer に解析させる。単語リストの作成にはもう少しきちんとした(句読点を考慮した)tokenizer が必要だが,ここでは,指定文字で語分割するごく単純な自前の split 関数ですませている。
// -*- coding: utf-8; -*-
// lemtest.cpp: Lemmatizer test programm.
// 2009 (c) isao yasuda.
#include <turglem/lemmatizer.hpp>
#include <turglem/russian/charset_adapters.hpp>
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstdio>
using namespace std;
// Lemmatizer
void lem_analyze(const tl::lemmatizer &lem, const char *s)
{
tl::lem_result lr; // instance for result of lemmatizer analyze.
size_t sz_lem = lem.lemmatize<russian_utf8_adapter>(s, lr);
if (sz_lem) {
printf("(lemmatize results: %zd)\n", sz_lem);
for (size_t i = 0; i < sz_lem; i++) {
printf(" ** %zd: paradigm/form = %04d/%02d", i,
lem.get_paradigm(lr, i),
lem.get_src_form(lr, i)
);
string nform = lem.get_text<russian_utf8_adapter>(lr, i, 0);
printf("\t\t\t\tNormal Form: '%s'\n", nform.c_str());
}
} else {
cout << "Empty result! Check your text." << endl;
}
}
// split 関数: 指定文字で文字列を分割
void split(const string &s, char c, vector<string> &v) {
string::size_type i = 0;
string::size_type j = s.find(c);
while (j != string::npos) {
v.push_back(s.substr(i, j-i));
i = ++j; j = s.find(c, j);
if (j == string::npos)
v.push_back(s.substr(i, s.length()));
}
}
// main
int main(int argc, char **argv)
{
tl::lemmatizer lem; // lemmatizer instance
string buffer;
ifstream in(argv[1]);
if (!in) {
cerr << "usage: " << argv[0] << " file-name" << endl;
return 1;
}
// load dict, etc.
try {
lem.load_lemmatizer(
"/usr/local/share/turglem/russian/dict_russian.auto",
"/usr/local/share/turglem/russian/paradigms_russian.bin",
"/usr/local/share/turglem/russian/prediction_russian.auto"
);
}
catch (const exception &e) {
cerr << "Error: " << e.what() << endl;
}
while (!in.eof()) {
vector<string> v;
getline(in, buffer, '\n');
if (!buffer.c_str()) continue;
split(buffer, ' ', v);
cout << buffer << endl;
for (int i = 0; i < v.size(); i++) {
cout << " " << i << " input word: " << v[i] << ' ';
// lemmatizer analyze.
try {
if (v[i].c_str()) lem_analyze(lem, v[i].c_str());
}
catch (const exception &e) {
cerr << "Error: " << e.what() << endl;
}
}
}
return 0;
}
コンパイルは以下のようにする。ライブラリの指定順序が違うとリンクでエラーとなる。
% g++ -I/usr/local/include -L/usr/local/lib -o lemtest lemtest.cpp \ -lturglem -lturglem-russian -lMAFSA
“lemtest 入力ファイル” で動く。試験入力内容と実行結果を以下に示す。
入力:
Я люблю вас
Саша прочитал книгу на русском языке
実行結果:
Я люблю вас
0 input word: Я (lemmatize results: 1)
** 0: paradigm/form = 2297/00 Normal Form: 'Я'
1 input word: люблю (lemmatize results: 1)
** 0: paradigm/form = 0913/01 Normal Form: 'ЛЮБИТЬ'
2 input word: вас (lemmatize results: 3)
** 0: paradigm/form = 0742/01 Normal Form: 'ВЫ'
** 1: paradigm/form = 0742/03 Normal Form: 'ВЫ'
** 2: paradigm/form = 0742/05 Normal Form: 'ВЫ'
Саша прочитал книгу на русском языке
0 input word: Саша (lemmatize results: 1)
** 0: paradigm/form = 2485/00 Normal Form: 'САША'
1 input word: прочитал (lemmatize results: 1)
** 0: paradigm/form = 0440/01 Normal Form: 'ПРОЧИТАТЬ'
2 input word: книгу (lemmatize results: 1)
** 0: paradigm/form = 0088/03 Normal Form: 'КНИГА'
3 input word: на (lemmatize results: 1)
** 0: paradigm/form = 0026/00 Normal Form: 'НА'
4 input word: русском (lemmatize results: 3)
** 0: paradigm/form = 0002/06 Normal Form: 'РУССКИЙ'
** 1: paradigm/form = 0002/19 Normal Form: 'РУССКИЙ'
** 2: paradigm/form = 0313/05 Normal Form: 'РУССКИЙ'
5 input word: языке (lemmatize results: 2)
** 0: paradigm/form = 0010/05 Normal Form: 'ЯЗЫК'
** 1: paradigm/form = 0021/05 Normal Form: 'ЯЗЫК'
"paradigm/form" に文法構造が示される。この数値で品詞,性・数・格などが示される。詳細は現在調査中である。"Normal Form" は見出し語である。
自作プログラムから Lemmatizer を呼出す方法の概略を,これで理解できた。そのうち,PCRE や Boost::regex などの正規表現ライブラリと組合わせて,コンコーダンス・プログラム,ロシア語旧正書法変換プログラムなどを開発したいと思っている。