LoginSignup
0
0

More than 5 years have passed since last update.

swi-prologで形態素解析

Last updated at Posted at 2019-03-29

文章を、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.


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0