C# Excelの列の26進数風(アルファベットのみ)の数列計算方法

Excel
スポンサーリンク
スポンサーリンク

したいこと

Excelの列で用いられている26進数風の数列(アルファベットのみ)を計算したい。
26進数風の数列(アルファベットのみ)にて、数値→アルファベット、アルファベット→数値の関数が欲しい。

計算したい理由

エクセルのセルの指定では数値指定できるのですが、一方で、表示はアルファベットのみの数列なので分かりにくいからです。下記の記事で数値でとっていますが、それではわかりにくいなぁと感じました。

VSTO エクセルでクリックしたセルの値を取得したい
したいこと VSTO エクセルでクリックしたセルの値を取得したい VSTO エクセルで選択したセルの値を取得するには 結論1 イベントハンドラが必要な場合 現在のシートにイベントハンドラを以下のように追加します。 ...

この画像のような、列側のアルファベットの数列です。

元ネタ

調査して、”[C#]エクセルの列名のようなアルファベットを返す関数”を参考にさせていただきました。

ソースコードとテスト

今回はただただコードを晒すだけの記事です。試してみてください。

テストコード(数値→アルファベット)

Assert.AreEqual("A", ExcelUtilityClass.GetColumnString(1), "指定したExcel Column値と異なります");
Assert.AreEqual("B", ExcelUtilityClass.GetColumnString(2), "指定したExcel Column値と異なります");
Assert.AreEqual("Z", ExcelUtilityClass.GetColumnString(26), "指定したExcel Column値と異なります");

Assert.AreEqual("AA", ExcelUtilityClass.GetColumnString(27), "指定したExcel Column値と異なります");
Assert.AreEqual("AZ", ExcelUtilityClass.GetColumnString(52), "指定したExcel Column値と異なります");
Assert.AreEqual("BA", ExcelUtilityClass.GetColumnString(53), "指定したExcel Column値と異なります");
Assert.AreEqual("BZ", ExcelUtilityClass.GetColumnString(78), "指定したExcel Column値と異なります");
Assert.AreEqual("ZZ", ExcelUtilityClass.GetColumnString(702), "指定したExcel Column値と異なります");

Assert.AreEqual("AAA", ExcelUtilityClass.GetColumnString(703), "指定したExcel Column値と異なります");
Assert.AreEqual("AAB", ExcelUtilityClass.GetColumnString(704), "指定したExcel Column値と異なります");

Assert.AreEqual("BAA", ExcelUtilityClass.GetColumnString(1379), "指定したExcel Column値と異なります");

Assert.AreEqual("ZAA", ExcelUtilityClass.GetColumnString(17603), "指定したExcel Column値と異なります");

Assert.AreEqual("ZZY", ExcelUtilityClass.GetColumnString(18277), "指定したExcel Column値と異なります");
Assert.AreEqual("ZZZ", ExcelUtilityClass.GetColumnString(18278), "指定したExcel Column値と異なります");

Assert.AreEqual("AAAA", ExcelUtilityClass.GetColumnString(18279), "指定したExcel Column値と異なります");

テストコード(アルファベット→数値)

Assert.AreEqual(475254, ExcelUtilityClass.GetColumnNumber("ZZZZ"), "指定したExcel Column値と異なります");
Assert.AreEqual(18279, ExcelUtilityClass.GetColumnNumber("AAAA"), "指定したExcel Column値と異なります");

Assert.AreEqual(18278, ExcelUtilityClass.GetColumnNumber("ZZZ"), "指定したExcel Column値と異なります");
Assert.AreEqual(18277, ExcelUtilityClass.GetColumnNumber("ZZY"), "指定したExcel Column値と異なります");
Assert.AreEqual(17603, ExcelUtilityClass.GetColumnNumber("ZAA"), "指定したExcel Column値と異なります");

Assert.AreEqual(1379, ExcelUtilityClass.GetColumnNumber("BAA"), "指定したExcel Column値と異なります");
Assert.AreEqual(1353, ExcelUtilityClass.GetColumnNumber("AZA"), "指定したExcel Column値と異なります");
Assert.AreEqual(703, ExcelUtilityClass.GetColumnNumber("AAA"), "指定したExcel Column値と異なります");

Assert.AreEqual(702, ExcelUtilityClass.GetColumnNumber("ZZ"), "指定したExcel Column値と異なります");


Assert.AreEqual(28, ExcelUtilityClass.GetColumnNumber("AB"), "指定したExcel Column値と異なります");
Assert.AreEqual(27, ExcelUtilityClass.GetColumnNumber("AA"), "指定したExcel Column値と異なります");

Assert.AreEqual(2, ExcelUtilityClass.GetColumnNumber("B"), "指定したExcel Column値と異なります");
Assert.AreEqual(1, ExcelUtilityClass.GetColumnNumber("A"), "指定したExcel Column値と異なります");

ソースコード


public class ExcelUtilityClass
{
    /// <summary>
    /// 数字 ⇒ Column(列・エクセル)変換 
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public static string GetColumnString(int index, int limitDigit = 5)
    {
        string str = "";

        int maxDigit = GetCurDigit(index);

        double[] maxPow = GetMaxDigitArray();

        for (int i = maxDigit; i >= 0; --i)
        {

            double pow = 0.0;

            pow = Math.Pow(26.0, i);

            // 26のi乗の商を計算
            double quotient = Math.Floor(index / pow);

            if (i != 0)
            {
                if (-0.000001 <= Math.Floor(index % pow) && Math.Floor(index % pow) <= 0.000001)
                {
                    quotient -= 1;
                }
                else if (quotient > 26)
                {
                    quotient = 26;
                }
            }


            char curDigit = (char)((int)quotient + 0x40);

            str = str + curDigit.ToString();

            // 上の桁を計算したので、下の桁へ移行
            index = index - (int)(quotient * pow);
        }

        return str;
    }


    /// <summary>
    /// 現在の桁数
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public static int GetCurDigit(int index)
    {
        int maxDigit = 20;

        double[] maxPow = GetMaxDigitArray();
        double[] minPow = new double[maxDigit];

        // アルファベット26進の桁の最小値 計算 
        // ( 例. 3桁なら 26*26 + 26 + 1 = AAA )

        minPow[0] = 1;
        for (int i = 1; i < minPow.Length; ++i)
        {
            minPow[i] = maxPow[i - 1] + 1;
        }


        int curDigit = 0;

        // indexが26の何乗か分の桁を持っているかを計算する
        for (int i = 0; i < maxPow.Length - 1; ++i)
        {
            if (minPow[i] <= index && index <= maxPow[i])
            {
                curDigit = i;
                break;
            }
        }

        return curDigit;
    }

    /// <summary>
    /// 最大桁の配列
    /// </summary>
    /// <returns></returns>
    private static double[] GetMaxDigitArray()
    {
        int maxDigit = 20;

        double[] maxPow = new double[maxDigit];

        // アルファベット26進の桁の最大値 計算 ( 例. 3桁なら 26*26*26 + 26*26 + 26 = ZZZ) 
        for (int i = 0; i < maxPow.Length; ++i)
        {
            maxPow[i] = Math.Pow(26.0, i + 1);

            for (int j = i; j > 0; --j)
            {
                maxPow[i] += Math.Pow(26.0, j);
            }
        }

        return maxPow;
    }

    /// <summary>
    /// Column(列・エクセル) ⇒ 数字 変換 
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public static int GetColumnNumber(string str)
    {
        int digit = str.Length;

        // 大文字に変換
        str = str.ToUpperInvariant();

        int result = 0;

        for (int i = 0; i < digit; ++i)
        {
            char c = Convert.ToChar(str.Substring(i, 1));

            int curDigit = c - 0x40;

            double pow = Math.Pow(26.0, digit - i - 1);

            result += curDigit * (int)pow;
        }

        return result;
    }
}
タイトルとURLをコピーしました