A1表記 (A1 notation)
表計算ソフトでは、行番号を通常の10進数、列番号をA
から始まる大文字のアルファベットを組み合わせた文字列により表します。
この方法では一番左上のセルが A1
という風に表されるため、この表記方法はA1表記と呼ばれています。
列番号は26種類の記号を使うから26進数じゃないの?
大文字のアルファベットは26種類なので、実質26進数なんじゃないの?という感じがしますが、一般的なn進数とは違った性質を持ちます。
なんとなく触っていると、思わぬ落とし穴にはまるかもしれません。
簡単にですが違いについて考えてみました。
10進数、26進数、A1表記の列番号の比較
- 0-9の記号を使った10進数
- A-Zの記号を使った26進数
- A1表記の列番号
この三つを比較してみましょう。
10進数 | 26進数 | A1表記 |
---|---|---|
0000 | AAAA | ---- |
0001 | AAAB | ---A |
0002 | AAAC | ---B |
... | ... | ... |
0025 | AAAZ | ---Y |
0026 | AABA | ---Z |
0027 | AABB | --AA |
0028 | AABC | --AB |
... | ... | ... |
一般的なn進数ではゼロに対応する記号があります。10進数だと"0", 26進では"A"です。
一方で、A1表記の列番号では、ゼロに対応する記号がありません。上の表では代わりに"-"を使ってそれを表現しています。もし"-"を"A"に置き換えた場合、二桁に繰り上がったときに2桁目が"A"で始まるため、扱いに困ってしまいます。
26進数では、(ゼロの場合を除いて)最上位の桁が"A"になることはないため、そういった問題は起こりません。
したがって、A1表記の列番号では桁数の情報を暗黙的に持っており、それが本質的な意味を持っているのでしょう。そして、その情報の分、26進数より同じ桁数でも表現の能力も高くなります。
A1表記の列番号から10進数への変換
\begin{equation}
f(d) =
\begin{cases}
0, & d = \mbox{'A'} \\
1, & d = \mbox{'B'} \\
2, & d = \mbox{'C'} \\
... \\
25, & z = \mbox{'Z'} \\
\end{cases}
\end{equation}
このように関数$f$を定義すると、26進数の10進数への変換は
\Sigma_{i=0}^{D_{max}}{f(D[i])*26^i}
と表せます。ただし、$D$は26進数の数で、$D[i]$は右からi番目の桁の文字を表し、$D{max}$は$D$の最大桁の番号を表すものとします。まあ、これは一般的な基数変換の計算ですね。
A1表記の列番号から10進数への変換は、各桁がゼロ始まりではなく1始まりなので、$f$の値に+1することで、
\Sigma_{i=0}^{D_{max}}{(f(D[i])+1)*26^i}
と表せます。
※26進数の場合は、最大桁の番号は必ずしも必要なわけではなく、これ以上大きなものはないという値(32bit整数における31のような値)が前もってわかっていれば、それでも構いません。
N文字で表される場合、表現できる数に$\Sigma_{i=0}^{N-1}{26^i}$だけ違いがあることがわかりました。
実装例 (Java)
26進数及びA1形式の列番号から、10進数への変換をJavaで実装してみます。
public class Main {
public static int f(char d) {
return d - 'A';
}
public static int fromBase26Num(String base26Num) {
int base10Num = 0;
for (int i = 0; i < base26Num.length(); i++) {
base10Num += (f(base26Num.charAt(base26Num.length() - 1 - i))) * Math.pow(26, i);
}
return base10Num;
}
public static int fromA1ColNum(String a1ColNum) {
int base10Num = 0;
for (int i = 0; i < a1ColNum.length(); i++) {
base10Num += (f(a1ColNum.charAt(a1ColNum.length() - 1 - i)) + 1) * Math.pow(26, i);
}
return base10Num;
}
public static void main(String[] args) {
System.out.println("【0が表示される】");
System.out.println(fromBase26Num("AAAA"));
System.out.println("【1が表示される】");
System.out.println(fromBase26Num("AAAB"));
System.out.println(fromA1ColNum("A"));
System.out.println("【27が表示される】");
System.out.println(fromBase26Num("AABB"));
System.out.println(fromA1ColNum("AA"));
}
}
実行結果
【0が表示される】
0
【1が表示される】
1
1
【27が表示される】
27
27
OK
まとめ
- A1形式の列番号は一般的な26進数ではない
- N桁だと、26進数より$\Sigma_{i=0}^{N-1}{26^i}$だけ表現できる数が多い
- 実装するときは気を付けましょう!
ここでは書かなかったですが、10進数からA1形式の列番号に変換するのはもっと面倒です。
https://github.com/ttk1/A1Util
需要があるかわかりませんが、ここに実装したものを置いています。(変数名・関数名がイケてないのはご容赦を!)
追記
10進数からA1形式の列番号に変換するのはもっと面倒です。
と書きましたが、@saka1029さんからのコメントの通り、思ったより面倒ではなかったです。