やりたいこと
Windows+pythonでMecab/Cabocha/KNPを使う時、楽しようとして「import mecab」や、「import Cabocha」を使うとリコンパイルやら、UTF-8指定やら、面倒くさくなる。
そこで、Sjift-Jis+外部呼び出しで、デフォルトインストールで使えるようにする。
環境
- Windows
- Mecab/Cabocha/Juman/KNPのインストール(SHIFT-JISで)
- Mecab/Cabocha/Juman/KNPは環境変数に通しておく
ソース
homefldrを任意の場所に設定すること
(2016/12/17 追記:KNPにも対応)
import os
import subprocess
from tempfile import NamedTemporaryFile
class JapaneseDependencyRelation:
def __init__(self, encoding=None):
if encoding is None:
encoding = 'utf-8'
# Mecab,CabochaのEncoding(インストール時に従う)
self.text_encoding = encoding
# TMPファイル作成場所
self.homefldr = 'C:\\tmp'
def get_encode_original(self, j_txt):
hoge = []
for ch in j_txt:
try:
hoge.append(ch.encode(self.text_encoding))
except:
raise UnicodeEncodeError
return ''.join(hoge)
def do_mecab(self, j_txt):
if os.path.exists(self.homefldr) == False:
raise FileNotFoundError
try:
with NamedTemporaryFile(delete=False, dir=self.homefldr) as temp:
try:
j_txt = j_txt.encode(self.text_encoding)
except:
j_txt = self.get_encode_original(j_txt)
temp.write(j_txt)
except Exception as e:
print(e)
raise UnicodeTranslateError
else:
command = ['mecab']
process = subprocess.Popen(command, stdin=open(temp.name, 'r'), stdout=subprocess.PIPE)
output = process.communicate()[0]
finally:
temp.close()
os.unlink(temp.name)
return output.decode(self.text_encoding)
def do_cabocha(self, j_txt, fmt=None):
if fmt is None:
fmt = "xml"
if os.path.exists(self.homefldr) == False:
raise FileNotFoundError
try:
with NamedTemporaryFile(delete=False, dir=self.homefldr) as temp:
try:
j_txt = j_txt.encode(self.text_encoding)
except:
j_txt = self.get_encode_original(j_txt)
temp.write(j_txt)
except Exception as e:
print(e)
raise UnicodeTranslateError
else:
'''
-f, --output-format=TYPE set output format style
0 - tree(default)
1 - lattice
2 - tree + lattice
3 - XML
'''
# cabocha引数
if (fmt == "xml"):
command = ['cabocha', '-f', '3']
elif (fmt == "tree"):
command = ['cabocha', '-f', '2']
else:
command = ['cabocha', '-f', '1']
process = subprocess.Popen(command, stdin=open(temp.name, 'r'), stdout=subprocess.PIPE)
output = process.communicate()[0]
finally:
temp.close()
os.unlink(temp.name)
return output.decode(self.text_encoding)
def do_knp(self, j_txt, fmt=None, level=None, output=None):
"""
解析結果の表示の指定(fmt)
-tab 表形式による表示(tab)
-simple 出力を少なくした表形式による表示(simple)
-td 「解析結果汎用表示ツール」1に対応した表示(td)
-tree (default) 木構造による表示(tree)
-bnsttab 文節の表形式による表示(tab1)
-bnsttree 文節の木構造による表示(tree1)
-sexp リスト形式による表示(sexp)
解析のレベルの指定(level)
-bnst 形態素列を文節列に変換する(1)
-dpnd さらに,文節間の係り受け解析を行う(2)
-case (default) さらに,格関係の解析を行う(3)
-anaphora さらに,照応関係の解析を行う(4)
-ne さらに,固有表現の解析を行う(5)
解析結果の出力情報の指定(output)
-normal (default) 最終的解析結果だけを表示(1)
-detail 係り受けの可能性行例,文節間の類似度行列なども表示(2)
-debug さらに詳しい解析途中段階の情報の表示(3)
"""
def set_argument(f, l, o):
arg = ['juman|knp']
if f == "tab":
arg.append("-tab")
elif f == "td":
arg.append("-td")
elif f == "tree":
arg.append("-tree")
elif f == "tab1":
arg.append("-bnsttab")
elif f == "tree1":
arg.append("-bnsttree")
elif f == "sexp":
arg.append("-sexp")
else:
arg.append("-simple")
if l == 1:
arg.append("-bnst")
elif l == 2:
arg.append("-dpnd")
elif l == 3:
arg.append("-case")
elif l == 5:
arg.append("-ne")
else:
arg.append("-anaphora")
if o == 2:
arg.append("-detail")
elif o == 3:
arg.append("-debug")
else:
arg.append("-normal")
return arg
if fmt is None:
fmt = "tab"
if level is None:
level = 4
if output is None:
output = 1
if os.path.exists(self.homefldr) == False:
raise FileNotFoundError
try:
with NamedTemporaryFile(delete=False, dir=self.homefldr) as temp:
try:
j_txt = j_txt.encode(self.text_encoding)
except:
j_txt = self.get_encode_original(j_txt)
temp.write(j_txt)
except Exception as e:
print(e)
raise UnicodeTranslateError
else:
command = set_argument(fmt, level, output)
process = subprocess.Popen(command, shell=True, stdin=open(temp.name, 'r'), stdout=subprocess.PIPE)
output = process.communicate()[0]
finally:
temp.close()
# TMPファイル削除
os.unlink(temp.name)
return output.decode(self.text_encoding)
if __name__ == "__main__":
operation_japanese = JapaneseDependencyRelation('shift-jis')
text = '隣の客はよく柿食う客だ'
# Mecab
print(operation_japanese.do_mecab(text))
# Cabocha
print(operation_japanese.do_cabocha(text, "xml"))
print(operation_japanese.do_cabocha(text, "tree"))
print(operation_japanese.do_cabocha(text, "word"))
# KNP
print(operation_japanese.do_knp(text, "tab"))
print(operation_japanese.do_knp(text, "td"))
print(operation_japanese.do_knp(text, "simple"))
print(operation_japanese.do_knp(text, "tree"))
print(operation_japanese.do_knp(text, "tab1"))
print(operation_japanese.do_knp(text, "tree1"))
print(operation_japanese.do_knp(text, "sexp"))