Try Golang! Spreadsheetのカラム文字列を数値に変換するライブラリ

Library to convert Spreadsheet column string to integer

筆者の過去のブログ(例えばこれ)を見ていただければ分かるように、Spreadsheetを使ったツールをよく作成しております。そして毎回思うことなのですが、カラム文字列を数値で定義するのが、地味に面倒なんです。具体的にはこんなコードです。

const (
columnMail = 3 // D
)

コメントを添えて間違えないよう気を付けていますが、このコメントが間違っていたら発狂モノです。また、数が多いと最初の設定だけで憂鬱。そこで今回は、これを解決するためにライブラリを作ってみました。その名もclmconv

使い方

使い方はいたって簡単です。Goの標準パッケージstrconvと同様、Atoiファンクションを用いて、カラム文字列を数値に変換できます。なお、ツールで使用する場合、インデックスはゼロ始まりが多いと思うので、"A"0を返します。

i, err := clmconv.Atoi("A") // i = 0

戻り値でerrorを受け取らなくて済むよう、MustAtoiも用意しています。こちらは、変換できない文字列が指定された場合、panicします。

i := clmconv.MustAtoi("A") // i = 0

あと、私はあまり使わないのですが、せっかくなので逆変換できるItoaも作成しました。単純な26進数になるかと思いきやそうでもなくて、ちょっと苦戦しました。

a := clmconv.Itoa(0) // a = "A"

もはや大きい数字は合ってるかわからないので、こちらのサイトを利用させていただきました。なお、こちらは1から始まるので、全て1ずつ結果がずれています。ちなみに、こちらは桁が大きくなると丸められてしまいます。clmconvは浮動小数点型は使用していないので丸め誤差は発生しませんが、int64の上限(カラム文字列だとCRPXNLSKVLJFHH!)を超えるとオーバーフローします。だれもこんな変換しないですよね。

Goのベンチマークで注意すること

ライブラリ作成中、ベンチマークを測っている時に、少し気になったことがあったので、備忘として残しておきます。今回、計測したベンチマークは、内部で使用しているpow26という26の累乗を返す関数です。再帰処理のため、メモ化した方が速いかな?でも、そんな大きい数の累乗はほとんど計算しないから、メモ化しない方がいいかな?と迷ったので、ベンチマークを測ってみました。

計測したのは、メモ化なしのPow26とメモ化ありのPow26WithMemo。あと、テストパッケージ内に同じ関数を用意し、Innerという接尾語を追加したものの、計4つです。結果はこちら(抜粋)。実行毎に多少ばらつきますが、だいたいこんな感じです。

BenchmarkPow26-4                  20000000     77.5 ns/op         BenchmarkPow26Inner-4             30000000     51.4 ns/op         BenchmarkPow26WithMemo-4          30000000     62.5 ns/op        BenchmarkPow26WithMemoInner-4     30000000     50.1 ns/op

実際に使用しない方は、テストパッケージ内に書けばいいかと思っていたのですが、上の結果から分かる通り、パッケージまたぎの呼び出しで結構オーバーヘッドがかかっています。厳密にチューニングする際には、これらの条件も揃えてテストしてあげないといけないということですね。

最終的には、math.Pow10を参考に、下記のような実装にしました。

var pow26tab = [...]int{1, 26, 676, 17576, 456976, 11881376}
func pow26(n int) int {
if 0 <= n && n <= 5 {
return pow26tab[n]
}
return pow26(n-1) * 26
}

ベンチマーク結果はこちら。いい感じに早くなっていますね!

BenchmarkPow26-4                  50000000      29.2 ns/op         BenchmarkPow26Inner-4             100000000     17.5 ns/op

かなりニッチなライブラリですが、個人的にはそこそこ使い勝手も良くて、結構満足。Spreadsheetを使ったツールを作成する人は少ないかもしれませんが、機会があれば、ぜひ使ってみてください!