ClojureでStringSearchを使う
Clojureからあいまい検索が可能なJavaライブラリを使いたい
「自分で実装してもいいけど、まあ誰か作っているだろう」という思いから見つけた記事がこれ↓
高速な文字列検索を実現するJavaライブラリ「StringSearch」
http://news.mynavi.jp/column/tool/044/
どうやらやりたいことはバッチリできそう。そして、ページを進むとサンプルコードまで書いてる優しさ。
私は決めました。Clojureからこれを使おうと。
本題
project.clj を編集
ありがたいことに、Clojars に StringSearch 1.2 があるので準備は簡単。
project.clj
のdependencies
を追加するだけ
https://clojars.org/org.clojars.nmurray.com.eaio/stringsearch
project.clj
:dependencies [[org.clojure/clojure "1.6.0"] [org.clojars.nmurray.com.eaio/stringsearch "1.2"]]
追加したあとは、lein deps
とかでライブラリのダウンロードを行ってください。
使ってみた
1からStringSearchのドキュメントを読むのもしんどかったので、先ほど記事のJavaコードをClojureに変換してみました。
以下のコードは参考程度に見てください。もっといい書き方がたくさんあるはず...
特にloop
を含んでるものは、元のJavaコードよりも変数が増えてしまっていてかなり残念...
; http://news.mynavi.jp/column/tool/045/ ; list 1 (def text (str "こんにちは世界。新世界へようこそ。")) (def pattern (str "世界")) (let [search (com.eaio.stringsearch.BoyerMooreHorspoolRaita.)] (println (str (inc (.searchString search text pattern)) "文字目"))) ;-> 6文字目
; http://news.mynavi.jp/column/tool/045/ ; list 2 (def text (str "こんにちは世界。新世界へようこそ。")) (def pattern (str "世界")) (let [search (com.eaio.stringsearch.BoyerMooreHorspoolRaita.) processed (.processString search pattern)] (loop [x -1] (let [y (.searchString search text (inc x) pattern processed)] (if (not (= y -1)) (do (println (str (inc y) "文字目")) (recur y)))))) ; -> ; 6文字目 ; 10文字目 ; nil
; http://news.mynavi.jp/column/tool/045/ ; list 3 (def text (str "こんにちは世界。新世紀へようこそ。")) (def pattern (str "世?")) (let [search (com.eaio.stringsearch.BNDMWildcards.) processed (.processString search pattern)] (loop [x -1] (let [y (.searchString search text (inc x) pattern processed)] (if (not (= y -1)) (do (println (str (inc y) "文字目")) (recur y)))))) ; -> ; 6文字目 ; 10文字目 ; nil
; http://news.mynavi.jp/column/tool/046/ ; list 1 (def text "Java, java, kava, Kava, sava, ^ava") (def pattern "[jJ]ava") (let [search (com.eaio.stringsearch.ShiftOrClasses.) processed (.processString search pattern)] (loop [x -1] (let [y (.searchString search text (inc x) pattern processed)] (if (not (= y -1)) (do (println (str (inc y) "文字目")) (recur y)))))) ; -> ; 1文字目 ; 7文字目 ; nil
; http://news.mynavi.jp/column/tool/046/ ; list 3 (def pattern "Java") (def text "Hello KaVa") ; (def text "Hello Java") ; (def text "Hello java") ; (def text "Hello JAVA") (let [search (com.eaio.stringsearch.ShiftOrMismatches.) processed (.processString search pattern 2)] (let [x (vec (.searchString search text pattern processed 2))] (println (str (inc (first x)) "文字目")) (println (str " " (second x) "文字のエラー"))))
おまけ1: import でオブジェクト生成を短く書く
(let [search (com.eaio.stringsearch.BoyerMooreHorspool.)] (println (str (inc (.searchString search text pattern)) "文字目")))
com.eaio.stringsearch.BoyerMooreHorspool.
って長いですよね...
Java同様、import
で短くしましょう。
(import '(com.eaio.stringsearch)) (let [search (BoyerMooreHorspool.)] (println (str (inc (.searchString search text pattern)) "文字目")))
または
(ns yournamespace (:import (com.eaio.stringsearch))) (let [search (BoyerMooreHorspool.)] (println (str (inc (.searchString search text pattern)) "文字目")))
おまけ2: 公式のドキュメントはどこに?
こちらが公式
http://johannburkard.de/software/stringsearch/
しかし、Doocumentation のページを辿っても Usage 的なものはないので…
StringSearch 1.2 tar.gz
をダウンロード・展開した先にあるindex.html
を読むのがおすすめ。(Javaだけど)
stringsearch-1.2/documentation/index.html
おまけ3: 日本語のあいまい検索がうまくいかない!
残念ながら、できません。
ShiftOrMismatches だけ日本語のようなマルチバイトに対応してません...
詳細は "おまけ2" でダウンロードしたファイルの中に書いてあります。
stringsearch-1.2/documentation/usage.html