GroongaのUTF-8なDBに対してShift_JIS（cp932）環境で全文検索する方法（.NET版）

[Groonga Advent Calendar 2015](http://qiita.com/advent-calendar/2015/groonga)の16日目の記事です。

# はじめに

GroongaはWindowsでも動かすことができます。動くことは動くのですが、日本語版Windowsではcmd.exeのデフォルトエンコーディングがcp932のため、Groongaのデータベースを作る際に `--encoding sjis` オプションの指定が必要な事が敷居を上げていました。 

ref: http://groonga.org/ja/docs/reference/executables/groonga.html?highlight=encoding#cmdoption--encoding

@myokoym さんが既にUTF-8なデータベースに対してWindowsで全文検索をするためのツールを公開されていますが、このツールはRubyで書かれているためGroongaの他にRuby InstallerなどでRubyのインストールが必要でした。

## Windowsでのお作法？

基本的にWindowsはユーザーランド（と一部カーネル空間）には高いバイナリ互換性があります。そして、Windows向けのプログラムを組む際にはMicrosoft社謹製のツールチェインやエコシステムを採用することでよりWindowsらしいツールとすることができます。

### .NET Frameworkとは

その中でも、Win32プラットフォームを一段ラップした環境を用意してくれる.NET Frameworkと呼ばれるものがあります。C#[^1] やVB、そしてF# などの言語が動くランタイムを提供してくれます。この用意してくれている環境を使わない手はありませんね！

[^1]: 今ではUnity C# Scriptの方が有名かもしれませんね。

## UTF-8を想定しているGroongaとの橋渡し

UTF-8を想定しているGroongaとの橋渡しをするには以下の条件を整える必要があります：

1. cp932エンコーディングの標準入力からUTF-8(cp65001)エンコーディングされた文字列をGroongaの標準入力へ渡す
2. UTF-8エンコーディングのGroongaの標準出力からcp932環境へ出力する

さて、これを実装してみましょう。

## 実装

.NETで動く言語は先に挙げたようにC#、Visual Basic、そしてF# などがあります。C#で実装すればMSDNに豊富な解説が転がっており、すぐできそうです。ただ、上記の性質を満たすのにC#でなければならない理由はなんでしょうか？特にないと思います。
特にF#は気軽に値にlet束縛と呼ばれる文法で名前を付けられるようになっています。

```fsharp
let a = 1
a // aという名前で参照できる
```

また、詳しくは解説しませんが型を書かなくても型推論により、静的型が補われてコンパイルされます。[^2]

[^2]: 先の例の`let a = 1`での`a`はint型に推論されます。

### エンコーディングの変換

.NET Frameworkではエンコーディングを変換するメソッドとして、[Encoding.Convert メソッド | MSDN](https://msdn.microsoft.com/ja-jp/library/kdcak6ye%28v=vs.110%29.aspx) を提供しています。これを使うと、cp932からUTF-8へ変換する関数はF#では次のようになります:

```fsharp
let convertLineToUTF8 (line: string) =
    // Create two different encodings.
    let shiftJIS = Encoding.GetEncoding("shift_jis")
    let utf8Bytes = Encoding.Convert(shiftJIS, utf8, shiftJIS.GetBytes(line.ToCharArray()))
    let utf8Str = Encoding.UTF8.GetString(utf8Bytes)
    utf8Str
```

.NETではエンコーディングを変換するときに一旦`byte[]`型を経由しなければならないのが少々面倒ですね。また、F#では型推論が効くので`convertLineToUTF8`関数の引数以外では型を書いていないのに注目してください。とても見やすくて、なおかつ型までついてお得感があります。[^3]

[^3]: 型が自明なのに書かないとコンパイルエラーになる言語に対して、型を気軽に手に入れることができるので、「型が軽い」と表現される事もあるようです。

ここまでで、`cp932エンコーディングの標準入力からUTF-8(cp65001)エンコーディングされた文字列をGroongaの標準入力へ渡す` ができることが分かりました。

次は `UTF-8エンコーディングのGroongaの標準出力からcp932環境へ出力する` を試してみましょう。

これが案外曲者です。cp932からUTF-8へはすんなりと変換できました、が、UTF-8からcp932はバイト数が削られる上に変換できない文字も出てきてしまいます。どうせなら.NET Framework組み込みで何か手立てがないか探してみましょう。

MSDNを探すと[ProcessStartInfo.StandardOutputEncoding プロパティ | MSDN](https://msdn.microsoft.com/ja-jp/library/system.diagnostics.processstartinfo.standardoutputencoding%28v=vs.110%29.aspx) を見つけることができます。つまり、以下のようにすることでプロセスの標準出力をリダイレクトしたうえで、cp932環境のcmd.exeへ文字化けせずに出力させることができるようになります。

```fsharp
let psInfo = new ProcessStartInfo("C:\\path\\to\\process")
psInfo.UseShellExecute <- false
psInfo.RedirectStandardOutput <- true
psInfo.RedirectStandardInput <- true
psInfo.Arguments <- @"Some process arguments"
psInfo.StandardOutputEncoding <- Encoding.UTF8
let p = Process.Start(psInfo)
```

さて、ここまでで実装の準備が整いました。これでUTF-8なGroongaのデータベースに対してcmd.exeなどから文字化けさせずに見ることのできるツールを作成することができそうです。

## grnline.fs

そうして出来上がったツールが[grnline.fs](https://github.com/cosmo0920/grnline.fs)です。

grnline.fsは.NET Framework 4.5に依存しているため、Microsoft .NET Framework 4.5のインストールが必要です。Windows 8以降であれば特に何かを新たにインストールする必要はありません。

GitHubのリリースページ機能を用いているため、[リリースページ| GitHub -- grnline.fs](https://github.com/cosmo0920/grnline.fs/releases) からgrnline-VERSION.zipをダウンロードして解凍するだけで使い始めることができます。

例えば、UTF-8なデータベースに対して対話型インターフェースを起動するには次のようにします：

```bat
> grnline.fs.exe --groonga-path C:\path\to\groonga --db-path C:\path\to\database --encoding UTF-8
```

## おわりに

GroongaのUTF-8なDBに対してcp932(Shift_JIS)環境で全文検索する**4**つ目の方法を解説しました。Windowsには.NET Frameworkという大変便利なエコシステムが備わっています。

これに乗っかるとWIN32アプリケーションと同様に実行バイナリとその設定、依存dll、そしてライセンス条項を期した文書を一緒に配布することで利用者に開発用のソフトウェアをインストールさせることなくツールを使用させることが可能になります。

.NETとGroongaの親和性が高まっていくとよいですね。
それではWindowsでも良い全文検索を！