エクセルの列名と列番号を変換するには

エクセルはセルを「A1」とか「AB10」のように英字の列と数字の行番号で指定するのだけど(A1スタイルと云うのかな)、たまに列番号で指定したいときもある。




ということで、列番号を渡すと列名を返すメソッドを作ってみる。このメソッドがあると、5列目を”E”列のように変換できるので、列番号で指定できるようになる。

        /// <summary>
        /// 列番号からエクセルの列名を得る (例 5 → "E")
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        static public string GetCellA1(int c)
        {
            string alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            string s = "";

            for (; c > 0; c = (c - 1) / 26 )
            {
                int n = (c - 1) % 26;
                s =  alpha.Substring(n, 1) + s;
            }
            return s;
        }


この種のメソッドを作るときに間違いやすいのが、1で始まるデータであるところ。上のコードでいえばfor文の3番目の式「c = (c - 1) / 26」を「c /= 26」と書いてしまったりする。そうすると、26が渡されたときにループをもう1回まわってしまって、"AA"に変換されてしまう。正しくは"Z"です。

上のメソッドをテストするのが次のコード。

        [TestMethod()]
        public void GetCellA1Test()
        {
            Assert.AreEqual(ExcelLib.Util.GetCellA1(1), "A");
            Assert.AreEqual(ExcelLib.Util.GetCellA1(26), "Z");
            Assert.AreEqual(ExcelLib.Util.GetCellA1(27), "AA");
            Assert.AreEqual(ExcelLib.Util.GetCellA1(702), "ZZ");
            Assert.AreEqual(ExcelLib.Util.GetCellA1(703), "AAA");

            for (int i = 1; i <= 26; i++)
            {
                string s = Convert.ToChar(Convert.ToInt32('A') + i - 1).ToString();
                Assert.AreEqual(ExcelLib.Util.GetCellA1(i), s);
            }
        }

前の投稿で文字コードのことを調べていたのは、このテストでアルファベット26文字分のテストをループを回して済ませたかったからなのでした。



逆に”A”を渡すと1を返すメソッドも作ってみる。

        /// <summary>
        /// エクセルの列名から列番号を得る(例:"A"→1)
        /// </summary>
        /// <param name="col"></param>
        /// <returns></returns>
        static public int getExcel列番号(string col)
        {
            string abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            int m = 0;

            for (int i = 0; i < col.Length; i++)
            {
                string c = col.Substring(i, 1);
                int n = abc.IndexOf(c) + 1;
                m += n * (int)Math.Pow(26, col.Length - i - 1);
            }

            return m;
        }

作った時期が違うので、メソッド名も引数もローカル変数名もバラバラですな、なかなか恥ずかしい。

そして単体テストがこちら。

        [TestMethod]
        public void Test_getExcel列番号()
        {
            Assert.AreEqual(mmExcel.getExcel列番号("A"), 1);
            Assert.AreEqual(mmExcel.getExcel列番号("B"), 2);
            Assert.AreEqual(mmExcel.getExcel列番号("C"), 3);
            Assert.AreEqual(mmExcel.getExcel列番号("AA"), 27);
            Assert.AreEqual(mmExcel.getExcel列番号("AAA"), 703);  // 26 * 27 + 1 = 26 * (26 + 1) + 1

            int c = Convert.ToInt32('A');

            for (int i = 0; i < 26; i++)
            {
                string s = Convert.ToChar(c + i).ToString();
                Assert.AreEqual(mmExcel.getExcel列番号(s), i + 1);
            }
        }

こうしてテストで確認できるようにしてあると、確かに安心。

コメント

このブログの人気の投稿

varchar をデータ型 numeric に変換中に、算術オーバーフロー エラーが発生しました。