たけっぱ横丁

the technical document for Vim(Editor), Natural Language Proecssing(NLP) tools and Programming(Python, Ruby, C++ etc).

Python3対応のMeCab(using subprocess)

Python3対応のMeCab

言語処理をされているかたならば,ご存知のMeCabですが
公式で配布されているパッケージがPython3に対応していなくて困ったことになります.

以下の記事では, python2のパッケージをpython3用に書きなおして pipで配布されているようです.

python3対応MeCabの紹介

インストールは非常に簡単で以下のいちコマンドで

pip install mecab-python3

これで今までのMeCabがPython3でも使えるようになりました.素敵!!

......

で終わるとなんだかつまんないですよね.

いつも思うことなのですが, こういうパーサー系のライブラリを使おうとすると,
その仕様を理解するのが色々面倒です.

出力を自分で直接パースしてしまうのが早かったりします.

またMeCabに限らず他のパーサをPythonで利用する時には結局自分でラッパーを書くしか無いので
パーサー系をラップするPythonを書くのは一度書いておくと何かと楽です.

Pythonでパーサーをラップする

ということでsubprocessを利用して, パーサをラップしたコードを書いてみました.

以下は分かち書き用のMeCab parserを抜き出したものです. コード全体はこちらです.
python3でも使えるように書かれています.

python2でsubprocessを利用するときの注意として,
Popen.communicate(input=None)には注意です. バッファサイズが小さいと入力によっては例外が投げられます.

python2でもtimeoutが設定できればよいのですが, (python3では設定できます)
無いので実装する際には, デットロックがかからないよう注意してください.

※例えば, 何もwriteしてない状態で, read()等を呼び出すとデットロックになります.

#Mecab implements for Python using subprocess
class MeCab():

    def __init__(self, opts=['-Owakati']):
        self.opts = opts
        self._process = subprocess.Popen(
            list(itt.chain(['mecab'], opts)),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            universal_newlines =True,
        )

    def parse(self, iterable):
        for line in iterable:
            self._process.stdin.write(line+'\n')
            output = self._process.stdout.readline()
            yield output.strip().split()

parser = MeCab()
print next(parser.parse(['すもももももももものうち']))
# >>> ['すもも', 'も', 'もも', 'も', 'もも', 'の', 'うち']

こういうのひとつ書いておくと, あとで他のパーサでも書きやすいので何かと楽です.