BathyScaphe ネタ(その37):乗り換えちゃった。
前回(d:id:tsawada2:20090815)述べた通り、BathyScaphe 内部で使用する正規表現使用のためのフレームワークを OgreKit から CocoaOniguruma に変更しました。svn にはもうコミットした。
乗り換えの最終段階で少しだけ困っていたのが、「後ろから検索」あるいは「前を検索」での正規表現利用の実装。BathyScaphe でいえば下の図の赤枠で囲った部分の組み合わせである:
正規表現を使わないときの検索、[]-[NSString rangeOfString:options:range][]
なら NSBackwardsSearch
オプションを指定すればいいし、OgreKit 使用時は []-[OGRegularExpression allMatchesInString:range:][]
で返される NSArray の lastObject を取ってくるような方法でやっていた。さて、CocoaOniguruma ではどうしよう?ヘッダファイルにはうまく使えそうなメソッドは無いので、前方から一つずつ検索していって検索範囲を縮めていき、最後のマッチを採用するというふうにコツコツ書くしか無いか?
…そう思っていたのだけど、もしやと思って元々の Oniguruma のドキュメントを読んだら、ちゃんと簡単な方法があることが分かった。
# int onig_search(regex_t* reg, const UChar* str, const UChar* end, const UChar* start, const UChar* range, OnigRegion* region, OnigOptionType option) 正規表現で文字列を検索し、検索結果とマッチ領域を返す。 正常終了戻り値: マッチ位置 (p - str >= 0) 検索失敗: ONIG_MISMATCH (< 0) 引数 1 reg: 正規表現オブジェクト 2 str: 検索対象文字列 3 end: 検索対象文字列の終端アドレス 4 start: 検索対象文字列の検索先頭位置アドレス 5 range: 検索対象文字列の検索終了位置アドレス 前方探索 (start <= 探索される文字列 < range) 後方探索 (range <= 探索される文字列 <= start) 6 region: マッチ領域情報(region) (NULLも許される) 7 option: 検索時オプション ONIG_OPTION_NOTBOL 文字列の先頭(str)を行頭と看做さない ONIG_OPTION_NOTEOL 文字列の終端(end)を行末と看做さない ONIG_OPTION_POSIX_REGION region引数をPOSIX APIのregmatch_t[]にする
(http://www.geocities.jp/kosako3/oniguruma/doc/API.ja.txt より引用)
要するに、検索対象の開始位置と終了位置を逆転して与えてやれば、「後ろから検索」「前を検索」になるということらしい。よって、これを CocoaOniguruma の OnigRegexp クラスに持ち上げて言い換えると、[]-[OnigRegexp search:start:end][]
の start
と end
に与える値を普通の検索のときと逆にしてあげれば良いということだ!
試してみてその通り、成功。かくして最後の課題も解決し、無事に乗り換えは完了した。これで体感的に何かが変わるという訳でもないが、前のエントリでも述べたように CocoaOniguruma はシンプルでこざっぱりしたフレームワークなので乗りこなしやすい。将来へ向けた安心感という意味では、ユーザの皆さんにとってもきっとメリットとなるであろう。……きっと!