【C++】Excelシートの列番号を算出する

 C++を使用して、Excelシートの列番号を例に、10進数と全単射26進数を相互に変換する方法を説明します。

開発環境Visual Studio 2022
言語C++
動作確認Windows 11
Windows 10
Windows 7
Ubuntu (g++)
FreeBSD (clang++)

 Excelシートの列番号の最大値は、XFD(16384 = 214)です。以下のような並びになります。サンプルソースは、FXSHRXW(2147483647 = INT_MAXの値)まで対応します。


10進数      ; 1,2,...,25,26,27,28,...,701,702,703,704,...,16383,16384
全単射26進数; A,B,..., Y, Z,AA,AB,..., ZY, ZZ,AAA,AAB,...,  XFC,  XFD

10進数から全単射26進数

 26で割った余りを、下の桁から上の桁に向かって、順番に並べていきます。数値とアルファベットの対応は、US-ASCII(A~Zは0x41~0x5A)から0x40を引きます。
(例)
16384 ÷ 26 = 630 余り 4 → D
630 ÷ 26 = 24 余り 6 → F
24 ÷ 26 = 0 余り 24 → X
より、XFD

 ただし、全単射26進数はゼロに相当するアルファベットが無く、26で桁が繰り上がらないので、「余りゼロ」を「余り26」として計算します。
(例)
26 ÷ 26 = 1 余り 0

26 ÷ 26 = 0 余り 26 → Z
とする


#include <string>

std::string base10to26(int n)
{
    int r = 0;
    std::string str;

    do
    {
        r = n % 26;
        n /= 26;

        if (!r)
        {
            r = 26;
            n--;
        }

        str.insert(str.begin(), 0x40 + r);
    }
    while (n > 0);

    return str;
}

全単射26進数から10進数

 アルファベットに対応する数値を、26を「下から何桁目-1」乗した値と掛けて、合計します。
(例)
XFD → 24、6、4
24 × 263 – 1 + 6 × 262 – 1 + 4 × 261 – 1 = 16384


#include <cmath>
#include <string>

int base26to10(std::string str)
{
    std::size_t size = str.size();
    int n = 0;

    for (std::size_t i = 0; i < size; i++)
    {
        n += (str[i] - 0x40) * static_cast<int>(std::pow(26, size - i - 1));
    }

    return n;
}

リファレンス

Bijective numeration
https://en.wikipedia.org/wiki/Bijective_numeration
「The bijective base-26 system」を参考にしました。