-
Notifications
You must be signed in to change notification settings - Fork 23
/
knp.py
161 lines (132 loc) · 6.09 KB
/
knp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
from pyknp import Juman, JUMAN_FORMAT
from pyknp import Socket, Subprocess
from pyknp import BList
import os
import unittest
import six
import distutils.spawn
class KNP(object):
""" KNPを用いて構文解析を行う/KNPの解析結果を読み取るモジュール
Args:
command (str): KNPコマンド
option (str): KNP解析オプション
(詳細解析結果を出力する-tabは必須。
省略・照応解析を行う -anaphora, 格解析を行わず構文解析のみを行う -dpnd など)
rcfile (str): KNP設定ファイルへのパス
pattern (str): KNP出力の終端記号
jumancommand (str): JUMANコマンド
jumanrcfile (str): JUMAN設定ファイルへのパス
jumanpp (bool): JUMAN++を用いるかJUMANを用いるか
"""
def __init__(self, command='knp', server=None, port=31000, timeout=60,
option='-tab', rcfile='', pattern=r'EOS',
jumancommand='jumanpp', jumanrcfile='',
jumanoption='', jumanpp=True):
self.command = command
self.server = server
self.port = port
self.timeout = timeout
self.options = option.split()
self.rcfile = rcfile
self.pattern = pattern
self.socket = None
self.subprocess = None
self.jumanpp = jumanpp
if self.rcfile and not os.path.isfile(os.path.expanduser(self.rcfile)):
raise Exception("Can't read rcfile (%s)!" % self.rcfile)
if distutils.spawn.find_executable(self.command) is None:
raise Exception("Can't find KNP command: %s" % self.command)
self.juman = Juman(command=jumancommand, rcfile=jumanrcfile,
option=jumanoption, jumanpp=self.jumanpp)
def knp(self, sentence):
""" parse関数と同じ """
self.parse(sentence)
def parse(self, sentence, juman_format=JUMAN_FORMAT.DEFAULT):
"""
入力された文字列に対して形態素解析と構文解析を行い、文節列オブジェクトを返す
Args:
sentence (str): 文を表す文字列
juman_format (JUMAN_FORMAT): Jumanのlattice出力形式
Returns:
BList: 文節列オブジェクト
"""
assert(isinstance(sentence, six.text_type))
juman_lines = self.juman.juman_lines(sentence)
juman_str = "%s%s" % (juman_lines, self.pattern)
return self.parse_juman_result(juman_str, juman_format)
def parse_juman_result(self, juman_str, juman_format=JUMAN_FORMAT.DEFAULT):
"""
JUMAN出力結果に対して構文解析を行い、文節列オブジェクトを返す
Args:
juman_str (str): ある文に関するJUMANの出力結果
juman_format (JUMAN_FORMAT): Jumanのlattice出力形式
Returns:
BList: 文節列オブジェクト
"""
if not self.socket and not self.subprocess:
if self.server is not None:
self.socket = Socket(
self.server, self.port, "RUN -tab -normal\n")
else:
command = [self.command] + self.options
if self.rcfile:
command.extend(['-r', self.rcfile])
self.subprocess = Subprocess(command)
if self.socket:
knp_lines = self.socket.query(juman_str, pattern=r'^%s$' % self.pattern)
else:
knp_lines = self.subprocess.query(juman_str, pattern=r'^%s$' % self.pattern)
return BList(knp_lines, self.pattern, juman_format)
def reparse_knp_result(self, knp_str, juman_format=JUMAN_FORMAT.DEFAULT):
"""
KNP出力結果に対してもう一度構文解析を行い、文節列オブジェクトを返す。
KNPのfeatureを再付与する場合などに用いる。中身はparse_juman_result関数と同じ。
Args:
knp_str (str): ある文に関するKNPの出力結果
juman_format (JUMAN_FORMAT): Jumanのlattice出力形式
Returns:
BList: 文節列オブジェクト
"""
return self.parse_juman_result(knp_str, juman_format=juman_format)
def result(self, input_str, juman_format=JUMAN_FORMAT.DEFAULT):
"""
ある文に関するKNP解析結果を文節列オブジェクトに変換する
Args:
input_str (str): ある文に関するKNPの出力結果
juman_format (JUMAN_FORMAT): Jumanのlattice出力形式
Returns:
BList: 文節列オブジェクト
"""
return BList(input_str, self.pattern, juman_format)
class KNPTest(unittest.TestCase):
def setUp(self):
self.knp = KNP()
def test_dpnd(self):
result = self.knp.parse("赤い花が咲いた。")
self.assertEqual(len(result), 3)
self.assertEqual(result[0].parent.bnst_id, 1)
self.assertEqual(len(result[1].children), 1)
self.assertEqual(result[1].children[0].bnst_id, 0)
self.assertEqual(result[1].parent.bnst_id, 2)
self.assertEqual(result[2].parent, None)
def test_mrph(self):
result = self.knp.parse("赤い花が咲いた。")
self.assertEqual(
''.join([mrph.midasi for mrph in result[0].mrph_list()]), '赤い')
self.assertEqual(
''.join([mrph.midasi for mrph in result[1].mrph_list()]), '花が')
self.assertEqual(
''.join([mrph.midasi for mrph in result[2].mrph_list()]), '咲いた。')
def test_mrph2(self):
result = self.knp.parse("エネルギーを素敵にENEOS")
self.assertEqual(
''.join([mrph.midasi for mrph in result[0].mrph_list()]), 'エネルギーを')
self.assertEqual(
''.join([mrph.midasi for mrph in result[1].mrph_list()]), '素敵に')
self.assertEqual(
''.join([mrph.midasi for mrph in result[2].mrph_list()]), 'ENEOS')
if __name__ == '__main__':
unittest.main()