ffi-aspell が便利なのでメモ

スペルチェックしてサジェストするの、どうやってるんだろうと思っていたけど、 GNU aspell というツールがあり、それの Ruby バインディングffi-aspell というのを見付けた。

インストール

まず aspell を入れる必要がある。 OSX なら以下のコマンドで入る。 aspell はデフォルトでは端末のロケールを見てスペルチェックしようとするけれど、日本語環境で使っているマシンでは「 ja_JP の辞書なんか無いよ」と言われるので --lang=en を付けておくこと。

brew install aspell --lang=en

あとは gem で ffi-aspell を入れればよい。

gem install ffi-aspell

使い方

基本的Speller インスタンスを生成して、そいつに単語を投げ付ける形になる。

speller = FFI::Aspell::Speller.new('en_US')

たとえば、天気を意味する weather を入力したいときに、間違えて wheather という単語を入力してしまった。この時サジェストして得られる結果は以下のようになる。

irb(main):006:0> speller.suggestions('wheather')
=> ["wheat her", "wheat-her", "weather", "whether", "Heather", "heather", "whither", "weathers", "wither", "feather", "leather", "sheathe", "wreathe", "weather's"]

本来欲しい結果である weather は 3 番目に出てきた。

aspell には suggestion_mode というものがあって、 normal だと音が似てる語をさがしてくるようになる。大抵は typo を直したいという用途だと思うので、 suggestion_modebad-spellers にしてみる。

irb(main):012:0> speller.suggestion_mode = 'bad-spellers'
=> "bad-spellers"

再度 wheather をサジェストしてみる。

irb(main):013:0> speller.suggestions('wheather')
=> ["weather", "whether", "wheat her", "wheat-her", "whither", "Heather", "heather", "wither", "weather's", "weathers", "feather", "leather", "sheathe", "wreathe", "worthier", "wealthier", "Heath", "ether", "heath", "watcher", "water", "wheat", "Cather", "Father", "Mather", "Rather", "Weaver", "bather", "either", "father", "gather", "hither", "lather", "nether", "rather", "sheath", "tether", "washer", "weaker", "wearer", "weaver", "wetter", "whaler", "whiter", "wreath", "Reuther", "Wheeler", "loather", "neither", "thither", "wearier", "whacker", "wheeler", "Whittier", "wheezier", "Heather's", "heather's", "theater", "heater", "heathen", "wheaten", "Wheaties", "breather", "cheater", "sheathed", "sheathes", "wreathed", "wreathes"]

大量の結果が出てくるようになったが今度は weather が 1 番目に出るようになった。

まとめ

GNU aspell と ffi-aspell を使えば手軽にスペルチェック・サジェストが出来るようになるので、人間が手で入力するなんらかのコマンドを受け付けるツールに組み込むとよさそう。

追記

aspell はあくまでスペルチェッカなので、限られた数のコマンド名から似ている語を探すだけであれば Damerau–Levenshtein 距離の近いコマンド名を探せばよさそうだということに気付きました。あとでやります。