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を使ったツールを作成する人は少ないかもしれませんが、機会があれば、ぜひ使ってみてください!