2016年11月22日火曜日

ソースコード中の単語からの略語/スペルミス検出に挑戦

2018/2/22 追記:続編書いた「続・ソースコード中の単語からの略語/スペルミス検出に挑戦」。Glosbe の制限の解決策も書いてあります。

ブログズミ: TreeTagger を使ってソースコード中の単語をリストアップしてみた」の続きです。
今回は抽出した単語が略語、もしくはスペルミスなどがないかチェックします。

なぜ、こんなものを作ったのか?それは


ということです。

今回作成したものはそのうちの一つで、「許可された略語以外は禁止」という規約に対して、その発見を"補助"するものです。
(あくまで補助でこれをかけて何も検出されなかったら OK というわけではありません。でも、人間が一語一語確認するものでもないので、これでも十分かなぁーっと思ってます。)

できたもの
最初に出来上がったものを紹介したいと思います。
ソースコードはこちらで公開しています。

usage: abbreviation.py [-h] [-v] [-g FILE] [-w FILE] [-e EXCLUDE]
                       [-a ABBREVIATION] [--glosbe] [--dejizo] [--cache]
                       [--load-cache NAME] [--cache-dir DIR] [--list-all]
                       FILE/DIR [FILE/DIR ...]

positional arguments:
  FILE/DIR              source code file/dir

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -g FILE, --gene FILE  exlude word
  -w FILE, --whitelist FILE
                        whitelist file
  -e EXCLUDE, --exclude EXCLUDE
                        exlude word
  -a ABBREVIATION, --abbreviation ABBREVIATION
                        abbreviation word
  --glosbe              use online translation service (glosbe)
  --dejizo              use online service (dejizo)
  --cache               online translation cache enable
  --load-cache NAME     load translation cache
  --cache-dir DIR       translation cache directory
  --list-all            list up all location

試しに iutest のソースコードを調べてみました。


設計としては、抽出した単語を辞書(オンライン/オフライン)から検索して、辞書にあれば問題なし(辞書に略語として登録されている場合は×)、辞書になかった場合に疑わしい単語として警告する設計です。

以下で詳しく説明していきます。

単語の抽出
「ソースコード中の単語」の抽出は libclang などを利用してやるほうが正しいとは思うのですが、
ブログズミ: TreeTagger を使ってソースコード中の単語をリストアップしてみた」でやったように形態素解析ツールの TreeTagger を使ってやりました。


オンライン辞書サービスを利用する
Glosbe
Glosbe Api
英単語の日本語訳をプログラム内やターミナル内で取得する - roombaの日記

いいね~いいね~とコーディングしていたら、いつの間にかエラーに…
Too many queries, your IP has been blocked

    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 429 Client Error:  for url: https://glosbe.com/gapi/translate?dest=ja&phrase=incg&from=en&pretty=true&format=json
というわけで、制限を超えてしまったようです…

ドキュメントによれば、「ブロックするリクエスト数は明確には決まってないけど、人間じゃなくてロボットだと判断したらブロックするよ」と書いてあります。

ロボットなのでしょうがないですね…
開発者でブロックされたら連絡してねとありますが、別のサービスを探すことにしました。
(一応、1日経つとブロック解除されています。今のところ)

WORDS API
WORDS API
無料プランでも 2,500 Requests/Day でよさそうだったんですが、クレジットの登録が必要だったので今回は保留としました。
(V-プリカとか使えば良いんですけど、めんどくさいので…)
(制限オーバーしたら請求が発生する感じに見えたのも保留した理由の1つ…)

デ辞蔵
デ辞蔵 オンラインでもオフラインでも使える電子辞書
続いて目をつけたのがこちら。
(SOAP ってなんだろ?って思ったんですが、そういうのがあったんですね)

こちらは特に制限がないのですが、注意事項として
・短時間にアクセスが集中するような呼び方(1秒間に20回以上の呼び出しなど)
・定常的に一定のアクセスが続くような呼び方(数秒ごとに自動的に呼び出すなど)
とありました。→「BizPal - デ辞蔵Tech よくある質問と回答
あと無償版は動作保証なし。

英和辞書で使えるのは、EDICT和英辞典(EJdict) と 三省堂 デイリーコンサイス英和辞典 試用版(DailyEJL)の2つあったので、両方を検索するようにしてます。ただし、 Glosbe よりも辞書の単語数は少ない印象
秒間20リクエストは場合によっては超えてるかもしれないので、ゴメンナサイm(__)m

その他
この記事も早く公開したいし、組み込みはこの辺で一旦終わりにしておきます。
その他の辞書サービスがあれば使ってみたいと思います。
あとは、翻訳サービス使う方法もありなのかも。

オンライン辞書のヒット結果をキャッシュする
さて、オンライン辞書から単語を引いてくることができるようになりましたが、リクエスト制限のことを考えなければいけません。というわけで、なるべくリクエストを投げないようにするために、一度検索ヒットした単語をローカルにキャッシュする仕組みを入れました。

今回 iutest を解析したときのキャッシュがリポジトリに入ってます。
このキャッシュはサービスごとに記録し、どんどん追記していく仕組みです。

また、キャッシュは2種類あります。
辞書には「略語」として単語登録されているものもありますので、ヒットしたけど略語だった場合はブラックリストに登録しています。
(※この略語判定が大変だった。特に EDICT は統一性がないのでかなり妥協…)

オフライン辞書を利用する
ソースコード中の単語で、外部に出したくないものもあると思います。(コードネームとか製品名とか?)
そこで、オフラインの辞書にも対応しています。

辞書は3つのタイプが利用可能です。

--whitelist FILE
単純な形式で単語を1行ずつ読み込みます。

--gene FILE
オープンしたファイルから、 '^[a-zA-Z][a-z]+$' にマッチするものを単語として読み込みます。
(これは GENE95 を想定して用意しているので、それ以外には使わないかもしれませんが…)

--cache-load XXX
オンライン辞書でキャッシュしたファイルを読み込みます。
XXX の部分にはオンライン辞書のオプション名を入れます。(現状、glosbe と dejizo のみ対応)
形式はホワイトリスト+ブラックリストになっています。

オンライン辞書では、場合によって "ver" などが "version" の略語として単語登録されている場合がありますので、
そのような単語はブラックリストとしてキャッシュしています。
(ホワイトリストの形式 --whitelist で読み込めるファイルと同じですので、これだけを --whitelist で読み込むことも可能です。)


使ってみた結果
当初は略語の検出を目的に作成しましたが、どちらかと言うと typo 、誤字脱字の方がよく検出される結果となりました。
(恥ずかしいのでちゃんと直しました。 > https://github.com/srz-zumix/iutest/commit/6c767630c810ef27b92bfca856a657209945433c

使ってみたい方、github で公開してますのでご自由にお使いください。




0 件のコメント:

コメントを投稿