文章を、jumanで形態素解析し、名詞を取り出す。jumanの場合、カテゴリ情報を追加している場合があるので、重要な要素なので、それも付加する。
juman.swi
%%
%% 文章から名詞のキーワード取得
%% jumanのカテゴリ情報を付加する
%%
%% TOP述語
keywords(String) :- juman(String,Lines),
getkeys(Lines,List),
write(List),!.
%% 再帰処理の終了条件
%% 最後は、Aが'EOS'のatomになっているはず
getkeys(A,[]) :- atom(A).
%% 念のために、空リストの場合も終わらせる
getkeys([],[]).
%% 本体、再帰的処理、splitはstringを返すので、名詞は、"名詞"でなければならない
%% stringは、swi-prologの拡張概念
%% split_string, nth1はswi-prologの拡張述語 manual参照
%% 名詞語を取得、カテゴリがある場合は付加する
getkeys(Lines,[Word|List]) :- [H|T]=Lines,
split_string(H,' ',' "',P),
nth1(1,P,A),
nth1(4,P,"名詞"),
getsublist(12,P,E),
getcategory(E,C),
%% ストリームの代わりにatom に書き込む swi-prologの拡張述語
format(atom(Word),'~s:~s',[A, C]),
getkeys(T,List),!.
%% カテゴリがない場合(上がどこかで失敗するので)
getkeys(Lines,[Word|List]) :- [H|T]=Lines,
split_string(H,' ',' ',P),
nth1(4,P,"名詞"),
nth1(1,P,Word),
getkeys(T,List).
%% 名詞でない場合、ただ次を調べる
getkeys(Lines,List) :- [_|T]=Lines,
getkeys(T,List).
%% 名詞の場合、カテゴリがついている可能性があるのでそれを取得する
%% カテゴリがリスト冒頭に見つかる
getcategory([H|_],C) :- split_string(H,':',':',P),
nth1(1,P,"カテゴリ"),
nth1(2,P,C),!.
%% 見つからなかったら、後尾を調べる
getcategory([_|T],C) :- getcategory(T,C).
%% I番目以降の要素でサブリストを作る builtinに見つからなかったので作成
%% 再帰の終了条件。インデクスIがリストLの長さを超えたら空をつなげて終わりにする
getsublist(I,L,[]) :- J is I-1,length(L,J),!.
%% 要素を再帰的につなげていく
getsublist(I,L,[A|S]) :- nth1(I,L,A),J is I+1,getsublist(J,L,S).
%%
%% juman 形態素解析実行
%% http://www.ibot.co.jp/wpibot/?p=2693 で解説済み
%% jumanを実行可能なパス上に置いておく
%%
juman(String, Lines) :-
setup_call_cleanup(
process_create(path(juman), [ ],
[ stdout(pipe(Out)), stdin(pipe(In))
]),
proc_stream(In, Out, String, Lines),
close(Out)).
proc_stream(In, Out, String, Lines) :-
write(In,String),
close(In),
read_line_to_codes(Out, Line1),
read_morpheme(Line1, Out, Lines).
read_morpheme(end_of_file, _, []) :- !.
read_morpheme(Codes, Out, [Line|Lines]) :-
atom_codes(Line, Codes),
read_line_to_codes(Out, Line2),
read_morpheme(Line2, Out, Lines).
実行例は次の通り。
?- ['juman.swi'].
true.
?- keywords('今日は良い天気ですね').
[今日:時間,天気:抽象物]
true.