# -*- encoding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
from pyknp import Argument, Pas
from pyknp import Bunsetsu
from pyknp import Morpheme, JUMAN_FORMAT
from pyknp import Tag
from pyknp import TList
from pyknp import SynNodes, SynNode
from pyknp import draw_tree, sprint_tree
import re
import unittest
import json
import bisect
[docs]class BList(object):
""" ある文に関する文節列を保持するオブジェクト
Args:
spec (str): KNP出力
pattern (str): KNP出力の終端記号
juman_format (JUMAN_FORMAT): Jumanのlattice出力形式
Attributes:
comment (str): KNP出力における、#から始まる行に書かれた文字列
sid (str): 文ID (KNP出力中のS-ID)
"""
[docs] def __init__(self, spec='', pattern='EOS', juman_format=JUMAN_FORMAT.DEFAULT):
self._bnst = []
self._readonly = False
self.pattern = pattern
self.juman_format = juman_format
self.comment = ''
self.sid = ''
self._pinfos = []
self.parse(spec)
self._set_parent_child()
self._set_positions()
self._set_pas(self.juman_format)
# set midasi
for i in range(len(self._bnst)):
self._bnst[i].set_midasi()
def _set_pas(self, juman_format):
""" 各基本句にPASを設定 """
tag_list = self.tag_list()
if juman_format != JUMAN_FORMAT.DEFAULT:
for pinfo in self._pinfos:
pinfo = json.loads(pinfo)
tag_idx = pinfo.get("tid")
if tag_idx is None:
end = pinfo["head_token_end"]
tag_idx = bisect.bisect(self.tag_positions, end) - 1
tag = tag_list[tag_idx]
tag.pas = Pas()
tag.pas.cfid = pinfo["cfid"]
for casename, args in pinfo["args"].items():
for arg in args:
arg_tag_idx = arg.get("tid")
if arg_tag_idx is None:
arg_tag_idx = bisect.bisect(self.tag_positions, arg["head_token_end"]) - 1
arg_sid = arg.get("sid")
if (arg_sid is None) or (len(arg["sid"]) == 0):
arg_sid = self.sid
arg = Argument(sid=arg_sid, tid=arg_tag_idx, midasi=arg["rep"])
tag.pas.arguments[casename].append(arg)
else:
# KNPの述語項構造をparse
for tag in tag_list:
if ("格解析結果" in tag.features) or ("述語項構造" in tag.features):
tag.pas = Pas(tag.tag_id, self)
[docs] def parse(self, spec):
""" KNPの出力を読み取る
Args:
spec (str): KNP出力
"""
for string in spec.split('\n'):
if string.strip() == "":
continue
if string.startswith('#\t'):
items = string.split("\t")
if len(items) >= 3 and items[1] == "PAS":
self._pinfos.append(items[2])
elif string.startswith('#'):
if self.comment:
self.comment += "\n"
self.comment += string
match = re.match(r'# S-ID: ?(\S*)( .+)?$', self.comment)
if match:
self.sid = match.group(1)
if 'KNP++' in string and 'output:KNP' not in string:
self.juman_format = JUMAN_FORMAT.LATTICE_TOP_ONE # TODO
elif re.match(self.pattern, string):
break
elif string.startswith(';;'):
raise Exception("Error: %s" % string)
elif string.startswith('*'):
bnst = Bunsetsu(string, len(self._bnst))
self._bnst.append(bnst)
elif string.startswith('+'):
if self.juman_format != JUMAN_FORMAT.DEFAULT: # TODO
bnst = Bunsetsu(string, len(self._bnst), self.juman_format)
self._bnst.append(bnst)
self._bnst[-1].push_tag(
Tag(string, len(self.tag_list()), self.juman_format))
elif string.startswith('!!'):
synnodes = SynNodes(string)
self._bnst[-1].tag_list().push_synnodes(synnodes)
elif string.startswith('!') and not string.startswith('! ! !'):
synnode = SynNode(string)
self._bnst[-1].tag_list().push_synnode(synnode)
elif string.strip() == 'EOS':
pass
else:
mrph = Morpheme(string, len(self.mrph_list()), self.juman_format)
if len(self._bnst) == 0:
bnst = Bunsetsu("*", len(self._bnst))
self._bnst.append(bnst)
self._bnst[-1].push_mrph(mrph)
def _set_positions(self):
mrphs = self.mrph_list()
if len(mrphs) == 0:
return
begin_position = mrphs[0].span[0]
self.mrph_positions = [begin_position]
self.tag_positions = [begin_position]
for mrph in self.mrph_list():
self.mrph_positions.append(self.mrph_positions[-1] + len(mrph.midasi))
for tag in self.tag_list():
start_mrph_index = tag.mrph_list()[0].mrph_index
end_mrph_index = tag.mrph_list()[-1].mrph_index
length = self.mrph_positions[end_mrph_index + 1] - self.mrph_positions[start_mrph_index]
self.tag_positions.append(self.tag_positions[-1] + length)
[docs] def get_tag_span(self, tag_id):
""" 基本句の位置情報を返す
Args:
tag_id (int): 基本句ID
Returns:
tuple: (基本句の開始位置, 終了位置)
"""
return self.tag_positions[tag_id], self.tag_positions[tag_id + 1] - 1
def _set_parent_child(self):
for bnst in self._bnst:
if bnst.parent_id == -1:
bnst.parent = None
else:
bnst.parent = self._bnst[bnst.parent_id]
self._bnst[bnst.parent_id].children.append(bnst)
for tag in bnst.tag_list():
if tag.parent_id == -1:
tag.parent = None
else:
tag.parent = self.tag_list()[tag.parent_id]
tag.parent.children.append(tag)
[docs] def push_bnst(self, bnst):
self._bnst.append(bnst)
self._bnst[bnst.parent].child.append(bnst.bnst_id)
[docs] def tag_list(self):
""" 文を構成する全基本句オブジェクトを返す
Returns:
list of Tag: 基本句オブジェクトTagのリスト
"""
return [tag for bnst in self._bnst for tag in bnst.tag_list()]
[docs] def mrph_list(self):
""" 文を構成する全形態素オブジェクトを返す
Returns:
list of Morpheme: 形態素オブジェクトMorphemeのリスト
"""
return [mrph for bnst in self._bnst for mrph in bnst.mrph_list()]
[docs] def bnst_list(self):
""" 文を構成する全文節オブジェクトを返す
Returns:
list of Bunsetsu: 文節オブジェクトBunsetsuのリスト
"""
return self._bnst
[docs] def set_readonly(self):
for bnst in self._bnst:
bnst.set_readonly()
self._readonly = True
[docs] def spec(self):
return "%s\n%s%s\n" % (self.comment, ''.join(b.spec() for b in self._bnst), self.pattern)
[docs] def all(self):
""" KNPの出力結果を返す """
return self.spec()
def __getitem__(self, index):
return self._bnst[index]
def __len__(self):
return len(self._bnst)
[docs] def draw_tree(self, fh=None, show_pos=True):
self.draw_bnst_tree(fh=fh, show_pos=show_pos)
[docs] def draw_bnst_tree(self, fh=None, show_pos=True):
""" 文節列の依存関係を木構造として表現して出力する. """
draw_tree(self._bnst, fh=fh, show_pos=show_pos)
[docs] def draw_tag_tree(self, fh=None, show_pos=True):
""" タグ列の依存関係を木構造として表現して出力する. """
tlist = TList()
for tag in self.tag_list():
tlist.push_tag(tag)
tlist.draw_tree(fh=fh, show_pos=show_pos)
[docs] def sprint_tree(self, show_pos=True):
return sprint_tree(self._bnst, show_pos=show_pos)
[docs] def get_clause_starts(self, concat_clause_in_paren=False, discourse_clause=False):
""" 節の冒頭句の位置情報を返す
Args:
concat_clause_in_paren (bool): 括弧内では節を切らないかどうか
discourse_clause (bool): 補文節、連体修飾節を切らないかどうか
Returns:
list: 節の冒頭となる基本句idのリスト
"""
starts = [0]
paren_level = 0
tags = self.tag_list()
for idx, tag in enumerate(tags):
features = tag.features # alias
if features.get("括弧始"):
paren_level += 1
elif features.get("括弧終"):
paren_level -= 1
if (not concat_clause_in_paren or paren_level == 0) and idx != len(tags) - 1:
if features.get("節-区切"):
if discourse_clause is True and (features.get("節-区切") == "連体修飾" or features.get("節-区切") == "補文"):
continue
else:
starts.append(idx + 1)
return starts
def __repr__(self):
return "BList(%s)" % repr(self.spec())
class BListTest(unittest.TestCase):
def setUp(self):
pass
def test1(self):
result = "# S-ID:123 KNP:4.2-ffabecc DATE:2015/04/10 SCORE:-18.02647\n" \
"* 1D <BGH:解析/かいせき><文頭><サ変><助詞><連体修飾><体言>\n" \
"+ 1D <BGH:構文/こうぶん><文節内><係:文節内><文頭><体言>\n" \
"構文 こうぶん 構文 名詞 6 普通名詞 1 * 0 * 0 \"代表表記:構文/こうぶん カテゴリ:抽象物\" <代表表記:構文/こうぶん>\n" \
"+ 2D <BGH:解析/かいせき><助詞><連体修飾><体言>\n" \
"解析 かいせき 解析 名詞 6 サ変名詞 2 * 0 * 0 \"代表表記:解析/かいせき カテゴリ:抽象物 ドメイン:教育・学習;科学・技術\" <代表表記:解析/かいせき>\n" \
"の の の 助詞 9 接続助詞 3 * 0 * 0 NIL <かな漢字><ひらがな><付属>\n" \
"* 2D <BGH:実例/じつれい><ヲ><助詞><体言><係:ヲ格>\n" \
"+ 3D <BGH:実例/じつれい><ヲ><助詞><体言><係:ヲ格>\n" \
"実例 じつれい 実例 名詞 6 普通名詞 1 * 0 * 0 \"代表表記:実例/じつれい カテゴリ:抽象物\" <代表表記:実例/じつれい>\n" \
"を を を 助詞 9 格助詞 1 * 0 * 0 NIL <かな漢字><ひらがな><付属>\n" \
"* -1D <BGH:示す/しめす><文末><句点><用言:動>\n" \
"+ -1D <BGH:示す/しめす><文末><句点><用言:動>\n" \
"示す しめす 示す 動詞 2 * 0 子音動詞サ行 5 基本形 2 \"代表表記:示す/しめす\" <代表表記:示す/しめす><正規化代表表記:示す/しめす>\n" \
"。 。 。 特殊 1 句点 1 * 0 * 0 NIL <英記号><記号><文末><付属>\n" \
"EOS"
blist = BList(result)
self.assertEqual(len(blist), 3)
self.assertEqual(len(blist.tag_list()), 4)
self.assertEqual(len(blist.mrph_list()), 7)
self.assertEqual(''.join([mrph.midasi for mrph in blist.mrph_list()]),
'構文解析の実例を示す。')
self.assertEqual(blist.sid, '123')
self.assertEqual(blist.all(), result + "\n")
# Check parent/children relations
self.assertEqual(blist[1].parent, blist[2])
self.assertEqual(blist[1].parent_id, 2)
self.assertEqual(blist[2].parent, None)
self.assertEqual(blist[2].parent_id, -1)
self.assertEqual(blist[1].children, [blist[0]])
self.assertEqual(blist[0].children, [])
self.assertEqual(blist.tag_list()[1].parent, blist.tag_list()[2])
self.assertEqual(blist.tag_list()[2].children, [blist.tag_list()[1]])
self.assertEqual(blist.mrph_positions, [0, 2, 4, 5, 7, 8, 10, 11])
self.assertEqual(blist.tag_positions, [0, 2, 5, 8, 11])
spans = [(0, 1), (2, 4), (5, 7), (8, 10)]
for i, t in enumerate(blist.tag_list()):
self.assertEqual(blist.get_tag_span(t.tag_id), spans[i])
def test2(self):
result = """# S-ID:foo KNP++:a9af601
+ 0 3 D 1;3 母が 母/ぼ - - - - - - - - - - BP:Phrase|CFG_RULE_ID:1|BOS|BP_TYPE|ガ|助詞
- 1 0 0 0 母 母/ぼ ぼ 母 名詞 6 普通名詞 1 * 0 * 0 漢字読み:音|漢字|CONT|RelWord-105522
- 3 1;2 1 1 が * が が 助詞 9 接続助詞 3 * 0 * 0 FUNC|T固有付属|T固有任意
+ 1 3 D 5;6 姉に 姉/あね - - - - - - - - - - BP:Phrase|CFG_RULE_ID:1|BP_TYPE|ニ|助詞|体言
- 5 3;4 2 2 姉 姉/あね あね 姉 名詞 6 普通名詞 1 * 0 * 0 漢字読み:訓|カテゴリ:人|漢字|CONT|LD
- 6 5 3 3 に * に に 助詞 9 接続助詞 3 * 0 * 0 FUNC|T固有付属|T固有任意
+ 2 3 D 8;9 弁当を 弁当/べんとう - - - - - - - - - - BP:Phrase|CFG_RULE_ID:1|BP_TYPE|ヲ
- 8 6;7 4 5 弁当 弁当/べんとう べんとう 弁当 名詞 6 普通名詞 1 * 0 * 0 カテゴリ:人工物-食べ
- 9 8 6 6 を * を を 助詞 9 格助詞 1 * 0 * 0 FUNC|T固有付属|T固有任意
+ 3 -1 D 10 渡した 渡す/わたす - - - - - - - - - - EOS|BP:Phrase|CFG_RULE_ID:0|BP_TYPE
- 10 9 7 9 渡した 渡す/わたす わたした 渡す 動詞 2 * 0 子音動詞サ行 5 タ形 10 付属動詞候補(基本)
# PAS {"predtype" : "PRED", "sid":"", "token_start":7, "token_end":9, "rep":"渡す/わたす", "head_token_start":7, "head_token_end":9, "cfid" : "渡す/わたす:動1", "score" : -27.2318, "args" : {"ヲ" : [{"sid":"", "token_start":4, "token_end":6, "rep":"弁当/べんとう", "head_token_start":4, "head_token_end":6}], "ガ" : [{"sid":"", "token_start":0, "token_end":1, "rep":"母/ぼ", "head_token_start":0, "head_token_end":1}], "ニ" : [{"sid":"", "token_start":2, "token_end":3, "rep":"姉/あね", "head_token_start":2, "head_token_end":3}]}}
EOS"""
blist = BList(result, juman_format=JUMAN_FORMAT.LATTICE_TOP_ONE)
self.assertEqual(len(blist), 4)
self.assertEqual(len(blist.tag_list()), 4)
self.assertEqual(len(blist.mrph_list()), 7)
self.assertEqual(''.join([mrph.midasi for mrph in blist.mrph_list()]),
'母が姉に弁当を渡した')
self.assertEqual(blist.sid, 'foo')
self.assertEqual(blist[1].parent, blist[3])
self.assertEqual(blist[1].parent_id, 3)
self.assertEqual(blist[3].parent, None)
self.assertEqual(blist[3].parent_id, -1)
self.assertEqual(blist[0].children, [])
self.assertEqual(blist[1].children, [])
self.assertEqual(blist[3].children, [blist[0], blist[1], blist[2]])
self.assertEqual(blist.tag_list()[1].parent, blist.tag_list()[3])
self.assertEqual(blist.tag_list()[3].children, [blist.tag_list()[0], blist.tag_list()[1], blist.tag_list()[2]])
self.assertEqual(blist.mrph_positions, [0, 1, 2, 3, 4, 6, 7, 10])
self.assertEqual(blist.tag_positions, [0, 2, 4, 7, 10])
spans = [(0, 1), (2, 3), (4, 6), (7, 9)]
tags = blist.tag_list()
for i, t in enumerate(tags):
self.assertEqual(blist.get_tag_span(t.tag_id), spans[i])
self.assertEqual(blist.get_clause_starts(), [0])
self.assertEqual(tags[0].pas, None)
self.assertEqual(tags[1].pas, None)
self.assertEqual(tags[2].pas, None)
self.assertEqual(tags[3].pas.cfid, "渡す/わたす:動1")
self.assertEqual(tags[3].features.pas.cfid, "渡す/わたす:動1")
args = tags[3].pas.arguments
self.assertEqual(len(args), 3)
self.assertEqual(len(args["ヲ"]), 1)
self.assertEqual(args["ヲ"][0].sid, "foo")
self.assertEqual(args["ヲ"][0].tid, 2)
class PasTest41(unittest.TestCase): # KNP v4.19
def setUp(self):
pass
def test(self):
spec = """
# S-ID:1 KNP:4.19-CF1.1 DATE:2018/10/19 SCORE:-22.05720
* 4D <文頭><SM-主体><SM-人><ハ><助詞><体言><一文字漢字><係:未格><提題><区切:3-5><主題表現><格要素><連用要素><正規化代表表記:彼/かれ><主辞代表表記:彼/かれ>
+ 4D <文頭><SM-主体><SM-人><ハ><助詞><体言><一文字漢字><係:未格><提題><区切:3-5><主題表現><格要素><連用要素><名詞項候補><先行詞候補><人称代名詞><正規化代表表記:彼/かれ><照応詞候補:彼><解析格:ガ><EID:0>
彼 かれ 彼 名詞 6 普通名詞 1 * 0 * 0 "代表表記:彼/かれ 漢字読み:訓 カテゴリ:人" <代表表記:彼/かれ><漢字読み:訓><カテゴリ:人><正規化代表表記:彼/かれ><文頭><漢字><かな漢字><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
は は は 助詞 9 副助詞 2 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* 2D <ヲ><助詞><体言><係:ヲ格><区切:0-0><格要素><連用要素><正規化代表表記:御飯/ごはん><主辞代表表記:御飯/ごはん>
+ 2D <ヲ><助詞><体言><係:ヲ格><区切:0-0><格要素><連用要素><名詞項候補><先行詞候補><正規化代表表記:御飯/ごはん><照応詞候補:ご飯><解析格:ヲ><EID:1>
ご飯 ごはん ご飯 名詞 6 普通名詞 1 * 0 * 0 "代表表記:御飯/ごはん カテゴリ:人工物-食べ物 ドメイン:料理・食事" <代表表記:御飯/ごはん><カテゴリ:人工物-食べ物><ドメイン:料理・食事><正規化代表表記:御飯/ごはん><かな漢字><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
を を を 助詞 9 格助詞 1 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* 4P <用言:動><係:連用><レベル:B><並キ:述:&レベル:強><区切:3-5><ID:動詞連用><連用要素><連用節><動態述語><正規化代表表記:食べる/たべる><主辞代表表記:食べる/たべる><並列類似度:1.587><並結句数:2><並結文節数:2><提題受:30>
+ 4P <用言:動><係:連用><レベル:B><並キ:述:&レベル:強><区切:3-5><ID:動詞連用><連用要素><連用節><動態述語><正規化代表表記:食べる/たべる><用言代表表記:食べる/たべる><提題受:30><格関係1:ヲ:ご飯><格解析結果:食べる/たべる:動1:ガ/U/-/-/-/-;ヲ/C/ご飯/1/0/1;ニ/U/-/-/-/-;ト/U/-/-/-/-;デ/U/-/-/-/-;カラ/U/-/-/-/-;ヨリ/U/-/-/-/-;マデ/U/-/-/-/-;ヘ/U/-/-/-/-;時間/U/-/-/-/-;外の関係/U/-/-/-/-;修飾/U/-/-/-/-;ノ/U/-/-/-/-;トスル/U/-/-/-/-;ニヨル/U/-/-/-/-;ニツク/U/-/-/-/-;トイウ/U/-/-/-/-;ニナラブ/U/-/-/-/-;ニツヅク/U/-/-/-/-;ニアワセル/U/-/-/-/-><EID:2><項構造:食べる/たべる:動1:ヲ/C/ご飯/1;ガ/N/彼/0>
食べ たべ 食べる 動詞 2 * 0 母音動詞 1 基本連用形 8 "代表表記:食べる/たべる ドメイン:料理・食事" <代表表記:食べる/たべる><ドメイン:料理・食事><正規化代表表記:食べる/たべる><かな漢字><活用語><連用形名詞化疑><自立><内容語><タグ単位始><文節始><文節主辞>
* 4D <ヘ><助詞><体言><係:ヘ格><区切:0-0><格要素><連用要素><正規化代表表記:大学/だいがく><主辞代表表記:大学/だいがく>
+ 4D <ヘ><助詞><体言><係:ヘ格><区切:0-0><格要素><連用要素><名詞項候補><先行詞候補><正規化代表表記:大学/だいがく><照応詞候補:大学><解析格:ヘ><EID:3><項構造:大学/だいがく:名0>
大学 だいがく 大学 名詞 6 普通名詞 1 * 0 * 0 "代表表記:大学/だいがく 組織名末尾 カテゴリ:場所-施設 ドメイン:教育・学習" <代表表記:大学/だいがく><組織名末尾><カテゴリ:場所-施設><ドメイン:教育・学習><正規化代表表記:大学/だいがく><漢字><かな漢字><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
へ へ へ 助詞 9 格助詞 1 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* -1D <文末><時制-過去><用言:動><レベル:C><区切:5-5><ID:(文末)><提題受:30><主節><動態述語><正規化代表表記:行く/いく?行う/おこなう><主辞代表表記:行く/いく?行う/おこなう>
+ -1D <文末><時制-過去><用言:動><レベル:C><区切:5-5><ID:(文末)><提題受:30><主節><動態述語><正規化代表表記:行く/いく?行う/おこなう><用言代表表記:行く/いく?行う/おこなう><主題格:一人称優位><格関係0:ガ:彼><格関係3:ヘ:大学><格解析結果:行く/いく:動1:ガ/N/彼/0/0/1;ヲ/U/-/-/-/-;ニ/U/-/-/-/-;ト/U/-/-/-/-;デ/U/-/-/-/-;カラ/U/-/-/-/-;ヨリ/U/-/-/-/-;マデ/U/-/-/-/-;ヘ/C/大学/3/0/1;時間/U/-/-/-/-;外の関係/U/-/-/-/-;修飾/U/-/-/-/-;ノ/U/-/-/-/-;トスル/U/-/-/-/-;ニツク/U/-/-/-/-;トイウ/U/-/-/-/-;ニカギル/U/-/-/-/-;ニヨル/U/-/-/-/-;ニアワセル/U/-/-/-/-><EID:4><項構造:行く/いく:動1:ヘ/C/大学/3;ガ/N/彼/0>
行った いった 行く 動詞 2 * 0 子音動詞カ行促音便形 3 タ形 10 "代表表記:行く/いく 付属動詞候補(タ系) ドメイン:交通 反義:動詞:帰る/かえる" <代表表記:行く/いく><付属動詞候補(タ系)><ドメイン:交通><反義:動詞:帰る/かえる><正規化代表表記:行く/いく?行う/おこなう><品曖><ALT-行った-おこなった-行う-2-0-12-10-"代表表記:行う/おこなう"><品曖-動詞><原形曖昧><文末><表現文末><移動動詞><かな漢字><活用語><自立><内容語><タグ単位始><文節始><文節主辞><用言曖昧性解消>
EOS
"""
# <項構造:行く/いく:動1:ヘ/C/大学/3;ガ/N/彼/0>
pas = Pas(tid=4, result=BList(spec))
self.assertEqual(pas.cfid, "行く/いく:動1")
self.assertEqual(pas.eid2tid, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
self.assertEqual(pas.arguments["ガ"][0].sid, "1")
self.assertEqual(pas.arguments["ガ"][0].tid, 0)
self.assertEqual(pas.arguments["ガ"][0].eid, 0)
self.assertEqual(pas.arguments["ガ"][0].midasi, "彼")
self.assertEqual(pas.arguments["ガ"][0].flag, "N")
self.assertEqual(pas.arguments["ガ"][0].sdist, 0)
class PasTest42(unittest.TestCase): # KNP v4.20
def setUp(self):
pass
def test1(self):
spec = """
# S-ID:1 KNP:4.2-a01607a1 DATE:2018/10/19 SCORE:-25.47925
* 4D <SM-主体><SM-人><BGH:彼/かれ><文頭><ハ><助詞><体言><一文字漢字><係:未格><提題><区切:3-5><主題表現><格要素><連用要素><正規化代表表記:彼/かれ><主辞代表表記:彼/かれ>
+ 4D <SM-主体><SM-人><BGH:彼/かれ><文頭><ハ><助詞><体言><一文字漢字><係:未格><提題><区切:3-5><主題表現><格要素><連用要素><名詞項候補><先行詞候補><人称代名詞><正規化代表表記:彼/かれ><主辞代表表記:彼/かれ><照応詞候補:彼><解析格:ガ><EID:5>
彼 かれ 彼 名詞 6 普通名詞 1 * 0 * 0 "代表表記:彼/かれ 漢字読み:訓 カテゴリ:人" <代表表記:彼/かれ><漢字読み:訓><カテゴリ:人><正規化代表表記:彼/かれ><漢字><かな漢字><名詞相当語><文頭><自立><内容語><タグ単位始><文節始><文節主辞>
は は は 助詞 9 副助詞 2 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* 2D <BGH:御飯/ごはん><ヲ><助詞><体言><係:ヲ格><区切:0-0><格要素><連用要素><正規化代表表記:御飯/ごはん><主辞代表表記:御飯/ごはん>
+ 2D <BGH:御飯/ごはん><ヲ><助詞><体言><係:ヲ格><区切:0-0><格要素><連用要素><名詞項候補><先行詞候補><正規化代表表記:御飯/ごはん><主辞代表表記:御飯/ごはん><照応詞候補:ご飯><解析格:ヲ><EID:6>
ご飯 ごはん ご飯 名詞 6 普通名詞 1 * 0 * 0 "代表表記:御飯/ごはん カテゴリ:人工物-食べ物 ドメイン:料理・食事" <代表表記:御飯/ごはん><カテゴリ:人工物-食べ物><ドメイン:料理・食事><正規化代表表記:御飯/ごはん><かな漢字><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
を を を 助詞 9 格助詞 1 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* 4P <BGH:食べる/たべる><用言:動><係:連用><レベル:B><並キ:述:&レベル:強><区切:3-5><ID:動詞連用><連用要素><連用節><動態述語><正規化代表表記:食べる/たべる><主辞代表表記:食べる/たべる><並列類似度:1.587><並結句数:2><並結文節数:2><提題受:30>
+ 4P <BGH:食べる/たべる><用言:動><係:連用><レベル:B><並キ:述:&レベル:強><区切:3-5><ID:動詞連用><連用要素><連用節><動態述語><正規化代表表記:食べる/たべる><主辞代表表記:食べる/たべる><用言代表表記:食べる/たべる><提題受:30><節-区切><節-主辞><格関係1:ヲ:ご飯><標準用言代表表記:食べる/たべる><EID:7><述語項構造:食べる/たべる:動1:ガ/N/彼/0/0/5;ヲ/C/ご飯/0/1/6;ニ/E/著者/2/-1/0;ト/-/-/-/-/-;デ/-/-/-/-/-;カラ/-/-/-/-/-;ヨリ/-/-/-/-/-;マデ/-/-/-/-/-;ヘ/-/-/-/-/-;時間/-/-/-/-/-;外の関係/-/-/-/-/-;修飾/-/-/-/-/-><省略解析信頼度:0.253><ガ格省略解析信頼度:0.000>
食べ たべ 食べる 動詞 2 * 0 母音動詞 1 基本連用形 8 "代表表記:食べる/たべる ドメイン:料理・食事" <代表表記:食べる/たべる><ドメイン:料理・食事><正規化代表表記:食べる/たべる><かな漢字><活用語><連用形名詞化疑><自立><内容語><タグ単位始><文節始><文節主辞><用言表記末尾>
* 4D <SM-主体><SM-場所><SM-組織><BGH:大学/だいがく><ヘ><助詞><体言><係:ヘ格><区切:0-0><格要素><連用要素><正規化代表表記:大学/だいがく><主辞代表表記:大学/だいがく>
+ 4D <SM-主体><SM-場所><SM-組織><BGH:大学/だいがく><ヘ><助詞><体言><係:ヘ格><区切:0-0><格要素><連用要素><名詞項候補><先行詞候補><正規化代表表記:大学/だいがく><主辞代表表記:大学/だいがく><照応詞候補:大学><解析格:ヘ><EID:8>
大学 だいがく 大学 名詞 6 普通名詞 1 * 0 * 0 "代表表記:大学/だいがく 組織名末尾 カテゴリ:場所-施設 ドメイン:教育・学習" <代表表記:大学/だいがく><組織名末尾><カテゴリ:場所-施設><ドメイン:教育・学習><正規化代表表記:大学/だいがく><漢字><かな漢字><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
へ へ へ 助詞 9 格助詞 1 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* -1D <BGH:行く/いく><文末><時制-過去><句点><用言:動><レベル:C><区切:5-5><ID:(文末)><係:文末><提題受:30><主節><格要素><連用要素><動態述語><正規化代表表記:行く/いく><主辞代表表記:行く/いく>
+ -1D <BGH:行く/いく><文末><時制-過去><句点><用言:動><レベル:C><区切:5-5><ID:(文末)><係:文末><提題受:30><主節><格要素><連用要素><動態述語><正規化代表表記:行く/いく><主辞代表表記:行く/いく><用言代表表記:行く/いく><節-区切><節-主辞><主題格:一人称優位><格関係0:ガ:彼><格関係3:ヘ:大学><標準用言代表表記:行く/いく><EID:9><述語項構造:行く/いく:動12:ガ/N/彼/0/0/5;ニ/E/著者/2/-1/0;ト/-/-/-/-/-;デ/-/-/-/-/-;カラ/-/-/-/-/-;ヨリ/-/-/-/-/-;マデ/-/-/-/-/-;ヘ/C/大学/0/3/8;時間/-/-/-/-/-;外の関係/-/-/-/-/-;修飾/-/-/-/-/-;ノ/-/-/-/-/-><省略解析信頼度:0.777><ガ格省略解析信頼度:0.000>
行った いった 行く 動詞 2 * 0 子音動詞カ行促音便形 3 タ形 10 "代表表記:行く/いく 付属動詞候補(タ系) ドメイン:交通 反義:動詞:帰る/かえる" <代表表記:行く/いく><付属動詞候補(タ系)><ドメイン:交通><反義:動詞:帰る/かえる><正規化代表表記:行く/いく><移動動詞><かな漢字><活用語><表現文末><自立><内容語><タグ単位始><文節始><文節主辞><用言表記末尾>
。 。 。 特殊 1 句点 1 * 0 * 0 NIL <英記号><記号><文末><付属>
EOS
"""
# <EID:7><述語項構造:食べる/たべる:動1:ガ/N/彼/0/0/5;ヲ/C/ご飯/0/1/6;ニ/E/著者/2/-1/0;ト/-/-/-/-/-;デ/-/-/-/-/-;カラ/-/-/-/-/-;ヨリ/-/-/-/-/-;マデ/-/-/-/-/-;ヘ/-/-/-/-/-;時間/-/-/-/-/-;外の関係/-/-/-/-/-;修飾/-/-/-/-/->
pas = Pas(tid=4, result=BList(spec))
self.assertEqual(pas.cfid, "行く/いく:動12")
self.assertEqual(pas.arguments["ガ"][0].sid, "1")
self.assertEqual(pas.arguments["ガ"][0].tid, 0)
self.assertEqual(pas.arguments["ガ"][0].eid, 5)
self.assertEqual(pas.arguments["ガ"][0].midasi, "彼")
self.assertEqual(pas.arguments["ガ"][0].flag, "N")
self.assertEqual(pas.arguments["ガ"][0].sdist, 0)
def test2(self):
spec = """
# S-ID:1 KNP:4.20-CF1.1 DATE:2020/08/04 SCORE:-41.95960
* 1D <文頭><感動詞><修飾><係:連用><区切:0-4><連用要素><連用節><正規化代表表記:こんにちは/こんにちは><主辞代表表記:こんにちは/こんにちは>
+ 1D <文頭><感動詞><修飾><係:連用><区切:0-4><連用要素><連用節><正規化代表表記:こんにちは/こんにちは>
こんにちは こんにちは こんにちは 感動詞 12 * 0 * 0 * 0 "代表表記:こんにちは/こんにちは" <代表表記:こんにちは/こんにちは><正規化代表表記:こんにちは/こんにちは><文頭><かな漢字><ひらがな><自立><内容語><タグ単位始><文節始><文節主辞>
* -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><正規化代表表記::/:><主辞代表表記::/:>
+ -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><判定詞><名詞項候補><先行詞候補><正規化代表表記::/:><用言代表表記::/:><時制-無時制><格解析結果::/::判0:ガ/U/-/-/-/->
: : : 名詞 6 普通名詞 1 * 0 * 0 "未知語:未対応文字種 品詞推定:特殊 疑似代表表記 代表表記::/: 品詞変更::-:-:-15-1-0-0" <未知語><品詞推定:特殊><疑似代表表記><代表表記::/:><正規化代表表記::/:><文末><表現文末><品詞変更::-:-:-15-1-0-0-"未知語:未対応文字種 品詞推定:特殊 疑似代表表記 代表表記::/:"><品曖-その他><記英数カ><英記号><記号><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
EOS
"""
# <格解析結果::/::判0:ガ/U/-/-/-/->
pas = Pas(tid=1, result=BList(spec))
self.assertEqual(pas.cfid, ":/::判0")
def test3(self):
spec = """
# S-ID:1 KNP:4.20-CF1.1 DATE:2020/08/03 SCORE:-45.92298
* 1D <文頭><サ変><サ変動詞><連体修飾><用言:動><係:連格><レベル:B><区切:0-5><ID:(動詞連体)><連体節><動態述語><正規化代表表記:表示/ひょうじ><主辞代表表記:表示/ひょうじ>
+ 1D <文頭><サ変動詞><連体修飾><用言:動><係:連格><レベル:B><区切:0-5><ID:(動詞連体)><連体節><動態述語><サ変><正規化代表表記:表示/ひょうじ><用言代表表記:表示/ひょうじ><時制-未来><格関係1:ガ:;><格解析結果:表示/ひょうじ:動2:ガ/N/;/1/0/1;ヲ/U/-/-/-/-;ニ/U/-/-/-/-;ト/U/-/-/-/-;デ/U/-/-/-/-;カラ/U/-/-/-/-;ヨリ/U/-/-/-/-;マデ/U/-/-/-/-;ヘ/U/-/-/-/-;時間/U/-/-/-/-;外の関係/U/-/-/-/-;ノ/U/-/-/-/-;修飾/U/-/-/-/-;ニヨル/U/-/-/-/-;トスル/U/-/-/-/-;ニツク/U/-/-/-/-;ニモトヅク/U/-/-/-/-;ニアワセル/U/-/-/-/-;ニタイスル/U/-/-/-/-;ニオク/U/-/-/-/->
表示 ひょうじ 表示 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:表示/ひょうじ カテゴリ:抽象物" <代表表記:表示/ひょうじ><カテゴリ:抽象物><正規化代表表記:表示/ひょうじ><文頭><漢字><かな漢字><名詞相当語><サ変><サ変動詞><自立><内容語><タグ単位始><文節始><文節主辞>
する する する 動詞 2 * 0 サ変動詞 16 基本形 2 "代表表記:する/する 自他動詞:自:成る/なる 付属動詞候補(基本)" <代表表記:する/する><自他動詞:自:成る/なる><付属動詞候補(基本)><正規化代表表記:する/する><とタ系連用テ形複合辞><かな漢字><ひらがな><活用語><付属>
* -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><正規化代表表記:;/;><主辞代表表記:;/;>
+ -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><判定詞><名詞項候補><先行詞候補><正規化代表表記:;/;><用言代表表記:;/;><時制-無時制><解析連格:ガ><格解析結果:;/;:判0:ガ/U/-/-/-/->
; ; ; 名詞 6 普通名詞 1 * 0 * 0 "未知語:その他 品詞推定:特殊 疑似代表表記 代表表記:;/; 品詞変更:;-;-;-15-1-0-0" <未知語><品詞推定:特殊><疑似代表表記><代表表記:;/;><正規化代表表記:;/;><文末><表現文末><品詞変更:;-;-;-15-1-0-0-"未知語:その他 品詞推定:特殊 疑似代表表記 代表表記:;/;"><品曖-その他><記英数カ><英記号><記号><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
EOS
"""
# <格解析結果:表示/ひょうじ:動2:ガ/N/;/1/0/1;ヲ/U/-/-/-/-;ニ/U/-/-/-/-;ト/U/-/-/-/-;デ/U/-/-/-/-;カラ/U/-/-/-/-;ヨリ/U/-/-/-/-;マデ/U/-/-/-/-;ヘ/U/-/-/-/-;時間/U/-/-/-/-;外の関係/U/-/-/-/-;ノ/U/-/-/-/-;修飾/U/-/-/-/-;ニヨル/U/-/-/-/-;トスル/U/-/-/-/-;ニツク/U/-/-/-/-;ニモトヅク/U/-/-/-/-;ニアワセル/U/-/-/-/-;ニタイスル/U/-/-/-/-;ニオク/U/-/-/-/->
pas = Pas(tid=0, result=BList(spec))
self.assertEqual(pas.cfid, "表示/ひょうじ:動2")
self.assertEqual(pas.arguments["ガ"][0].sid, "1")
self.assertEqual(pas.arguments["ガ"][0].tid, 1)
self.assertEqual(pas.arguments["ガ"][0].midasi, ";")
self.assertEqual(pas.arguments["ガ"][0].flag, "N")
self.assertEqual(pas.arguments["ガ"][0].sdist, 0)
def test4(self):
spec = """
# S-ID:1 KNP:5.0-165d699a DATE:2020/08/13 SCORE:-8.40889
* 1D <BGH:束の間/つかのま><文頭><時間><ガ><助詞><体言><判定詞><用言:判><係:連用><レベル:C><並キ:述:&ST:3.5&&&レベル:B><区切:3-5><ID:〜が><提題受:30><連用要素><連用節><状態述語><敬語:丁寧表現><正規化代表表記:束の間/つかのま><主辞代表表記:束の間/つかのま><並列類似度:1.258>
+ 1D <BGH:束の間/つかのま><文頭><時間><ガ><助詞><体言><判定詞><用言:判><係:連用><レベル:C><並キ:述:&ST:3.5&&&レベル:B><区切:3-5><ID:〜が><提題受:30><連用要素><連用節><状態述語><敬語:丁寧表現><節-機能-逆接:〜が><判定詞句><名詞項候補><先行詞候補><正規化代表表記:束の間/つかのま><主辞代表表記:束の間/つかのま><用言代表表記:束の間/つかのま><CF_NOT_FOUND><節-区切><節-主辞><時制:非過去><照応詞候補:束の間><標準用言代表表記:束の間/つかのま><EID:5><述語項構造:束の間/つかのま:判0>
束の間 つかのま 束の間 名詞 6 普通名詞 1 * 0 * 0 "代表表記:束の間/つかのま カテゴリ:時間" <代表表記:束の間/つかのま><カテゴリ:時間><正規化代表表記:束の間/つかのま><かな漢字><名詞相当語><文頭><自立><内容語><タグ単位始><文節始><文節主辞><用言表記先頭><用言表記末尾><用言意味表記末尾>
です です だ 判定詞 4 * 0 判定詞 25 デス列基本形 27 NIL <かな漢字><ひらがな><活用語><付属>
が が が 助詞 9 接続助詞 3 * 0 * 0 NIL <かな漢字><ひらがな><付属>
* -1D <BGH:する/する><文末><サ変><句点><用言:動><レベル:C><区切:5-5><ID:(文末)><係:文末><提題受:30><主節><格要素><連用要素><動態述語><敬語:丁寧表現><正規化代表表記:ゲーム/げーむ><主辞代表表記:ゲーム/げーむ>
+ -1D <BGH:する/する><文末><句点><用言:動><レベル:C><区切:5-5><ID:(文末)><係:文末><提題受:30><主節><格要素><連用要素><動態述語><敬語:丁寧表現><サ変><正規化代表表記:ゲーム/げーむ><主辞代表表記:ゲーム/げーむ><用言代表表記:ゲーム/げーむ><節-区切><節-主辞><時制:非過去><主題格:一人称優位><標準用言代表表記:ゲーム/げーむ><EID:6><述語項構造:ゲーム/げーむ:動2:ガ/E/著者/2/-1/0;ニ/E/不特定-人/2/-1/2;ト/-/-/-/-/-;デ/-/-/-/-/-;カラ/-/-/-/-/-;マデ/-/-/-/-/-;時間/-/-/-/-/-;修飾/-/-/-/-/-;外の関係/-/-/-/-/-><省略解析信頼度:0.076><ガ格省略解析信頼度:0.000>
ゲーム げーむ ゲーム 名詞 6 普通名詞 1 * 0 * 0 "代表表記:ゲーム/げーむ ドメイン:レクリエーション カテゴリ:抽象物" <代表表記:ゲーム/げーむ><ドメイン:レクリエーション><カテゴリ:抽象物><正規化代表表記:ゲーム/げーむ><記英数カ><カタカナ><名詞相当語><サ変><自立><内容語><タグ単位始><文節始><固有キー><文節主辞><用言表記先頭><用言表記末尾><用言意味表記末尾>
し し する 動詞 2 * 0 サ変動詞 16 基本連用形 8 "代表表記:する/する 自他動詞:自:成る/なる 付属動詞候補(基本)" <代表表記:する/する><自他動詞:自:成る/なる><付属動詞候補(基本)><正規化代表表記:する/する><かな漢字><ひらがな><活用語><とタ系連用テ形複合辞><付属>
ます ます ます 接尾辞 14 動詞性接尾辞 7 動詞性接尾辞ます型 31 基本形 2 "代表表記:ます/ます" <代表表記:ます/ます><正規化代表表記:ます/ます><かな漢字><ひらがな><活用語><表現文末><付属>
。 。 。 特殊 1 句点 1 * 0 * 0 NIL <英記号><記号><文末><付属>
EOS
"""
# <述語項構造:束の間/つかのま:判0>
pas = Pas(tid=0, result=BList(spec))
self.assertEqual(pas.cfid, "束の間/つかのま:判0")
self.assertEqual(len(pas.arguments), 0)
def test5(self):
spec = """
# S-ID:1 KNP:4.20-CF1.1 DATE:2020/08/04 SCORE:-41.95960
* 1D <文頭><感動詞><修飾><係:連用><区切:0-4><連用要素><連用節><正規化代表表記:こんにちは/こんにちは><主辞代表表記:こんにちは/こんにちは>
+ 1D <文頭><感動詞><修飾><係:連用><区切:0-4><連用要素><連用節><正規化代表表記:こんにちは/こんにちは>
こんにちは こんにちは こんにちは 感動詞 12 * 0 * 0 * 0 "代表表記:こんにちは/こんにちは" <代表表記:こんにちは/こんにちは><正規化代表表記:こんにちは/こんにちは><文頭><かな漢字><ひらがな><自立><内容語><タグ単位始><文節始><文節主辞>
* -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><正規化代表表記::/:><主辞代表表記::/:>
+ -1D <文末><体言><用言:判><体言止><レベル:C><区切:5-5><ID:(文末)><裸名詞><提題受:30><主節><状態述語><判定詞><名詞項候補><先行詞候補><正規化代表表記::/:><用言代表表記::/:><時制-無時制><格解析結果::/::判0:ガ/U/-/-/-/->
: : : 名詞 6 普通名詞 1 * 0 * 0 "未知語:未対応文字種 品詞推定:特殊 疑似代表表記 代表表記::/: 品詞変更::-:-:-15-1-0-0" <未知語><品詞推定:特殊><疑似代表表記><代表表記::/:><正規化代表表記::/:><文末><表現文末><品詞変更::-:-:-15-1-0-0-"未知語:未対応文字種 品詞推定:特殊 疑似代表表記 代表表記::/:"><品曖-その他><記英数カ><英記号><記号><名詞相当語><自立><内容語><タグ単位始><文節始><文節主辞>
EOS
"""
blist = BList(spec)
new_blist = eval(repr(blist))
self.assertEqual(blist.spec(), new_blist.spec())
if __name__ == '__main__':
unittest.main()