どうせ和布蕪るなら、の続き、らしいのだぜ (ライブラリらしい利用の続きらしいのだぜ)

こいつへの追記で済まそうか迷ったんだけどね、一個のネタ以上のことを書きたくなったもんで。

和布蕪づいた発端の「subprocess な MeCab 利用」を再掲:

 1 # -*- coding: utf-8 -*-
 2 from __future__ import unicode_literals
 3 
 4 import re
 5 import subprocess
 6 
 7 
 8 _mecab_path = "c:/Program Files (x86)/MeCab/bin/mecab"
 9 
10 
11 #
12 def _call_mecab(s):
13     p = subprocess.Popen(
14         [_mecab_path],
15         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
16     return p.communicate(s.encode("utf-8"))[0].decode("utf-8")
17 
18 
19 #
20 def _split_mecab_result(s):
21     paras_toks = [
22         x.rstrip() for x in re.split(r"^EOS\r?$", s, flags=re.M)
23         if x.rstrip()]
24     #
25     return [
26         [
27             [f.split(",") if i == 1 else f
28              for i, f in enumerate(line.split("\t"))]
29             for line in re.split("\r?\n", x) if line]
30         for x in paras_toks]
31 
32 
33 #
34 def wakati(s):
35     paras = _split_mecab_result(_call_mecab(s))
36     result = []
37     for para in paras:
38         tmp = []
39         for i, (sur, inf) in enumerate(para):
40             dont = False
41             if inf[1] in ("句点", "読点"):
42                 dont = True
43             if i > 0 and not dont:
44                 tmp.append(" " + sur)
45             else:
46                 tmp.append(sur)
47         result.append("".join(tmp))
48     return result
49 
50 
51 #
52 if __name__ == '__main__':
53     print("\n".join(
54         wakati(
55             """\
56 Perfume×伊勢丹コラボ!新PV制作、ハイヒール販売、館内マップも ナタリー
57 『bridge』vol.56 p.154のっち第4発言
58 """)))

これを「せっかくライブラリとして使えるようになったので」な話。こういうことだね:

 1 # -*- coding: utf-8 -*-
 2 import MeCab
 3 from MeCab import Tagger
 4 
 5 #
 6 def wakati(s):
 7     result = []
 8     for line in s.split("\n"):
 9         result.append("")
10         t = Tagger.create("-F%f[1]")  # 品詞細分類1
11         node = t.parseToNode("ダミー " + line)
12         node = node.next.next
13         while node:
14             if node.stat in (
15                 MeCab.MECAB_BOS_NODE,
16                 MeCab.MECAB_EOS_NODE):
17                 pass
18             else:
19                 sur, sd1 = node.surface, t.formatNode(node)
20                 if sd1 in ("句点", "読点") or not result[-1]:
21                     result[-1] += sur
22                 else:
23                     result[-1] += " " + sur
24             node = node.next
25     return result
26 
27 
28 #
29 if __name__ == '__main__':
30     print("\n".join(
31         wakati(
32             """\
33 Perfume×伊勢丹コラボ!新PV制作、ハイヒール販売、館内マップも ナタリー
34 『bridge』vol.56 p.154のっち第4発言
35 """)))

一つ前ので書いたように、最初のノードの surface がどうしてもおかしい(ので「ダミー」を追加して誤魔化してる)んだけれど、もうひとつ気付いたことがあって。未知語は formatNode にどうやっても surface が入ってこないのね、なのでこれはどうしても node.surface から取らなければならない。

まぁ…もとの subprocess のよりもシンプルには書けるのは確かだけれど、「壊れた振る舞い対応」は気色悪くて、果たしてこれが楽なんだろうか、ということではある。「64bit版ビルド」にもうひと手間以上必要ということなのか、あるいは先天的に MeCab そのものが問題を抱えているのか、あるいは Swig での連携が何かマズイのか。「理想的な状態」であっても気色悪いコーディングは残る(formatNode のインターフェイスのせい)ので、なんならこれでもいっか、という気分になるのはさらに気色悪い。なんだかなぁ。


さて。これはこれとして。

正直ねぇ、なんかもう MeCab 本体に手を入れたくて仕方ない気分。MeCab のコアに関しては何の不満もないわさ。けどね、「ソフトウェアとして」「ライブラリとして」はかなり気に入らないし、かなりインターフェイスがダメ。

これね、おそらくライブラリ化は後付けで取ってつけなんだと思う。mecabrc も同じく。まぁプログラムの作り方としてそういう進め方もありだとは思うんだけれど、「単なる CUI」としてプロジェクトを開始して、最後の最後にライブラリ化を付け足した、ということが良くわかるプログラムになっている。読めばわかるよ、「ライブラリとしてのエントリポイント」が「int argc, char** argv」を受け取ってる。つまり main で受け取るものを「再利用するインターフェイス」になってる。驚くべきことに、これは mecabrc も同じ。コマンドラインオプションと同じインターフェイスでパラメータを更新するようになっている。「合理的」とも言えるんだけれども、少なくとも利用者の気持ちには寄り添ってない。要するに「インチキ」。

だので、はっきりいって「ライブラリ化部分」だけをまっさらにして考え直して、完全に書き直せば、かなり使いやすいものになると思うし、しかもそれ、めちゃくちゃ簡単に作業出来ると思う。おそらくワタシがかかりっきりで作業すれば数日で完了できる。

…そうなん…だけれども。やらないよ。アクティブなプロジェクトならともかく、このプロジェクト、既に2015年からまったく更新のない、不活性なプロジェクトなんだから。やってもいいけど、その場合は「おれのためだけに、誰にも公開しないもの」としてしかやらない。正直、そやつのメンテナンスにコストをかけたくない。何度でも言うよ、「アクティブなプロジェクトだったらたぶんやってる、けどアクティブでないのでやらない」。

なんとも勿体無いプロジェクトだなぁ、って思う。ほんと、最後の最後の仕上げだけ失敗してるて感じ。

というかこれが言いたくて、これへの追記にしなかった。



Related Posts