エクセルの列名と列番号を変換するには
エクセルはセルを「A1」とか「AB10」のように英字の列と数字の行番号で指定するのだけど(A1スタイルと云うのかな)、たまに列番号で指定したいときもある。
ということで、列番号を渡すと列名を返すメソッドを作ってみる。このメソッドがあると、5列目を”E”列のように変換できるので、列番号で指定できるようになる。
この種のメソッドを作るときに間違いやすいのが、1で始まるデータであるところ。上のコードでいえばfor文の3番目の式「c = (c - 1) / 26」を「c /= 26」と書いてしまったりする。そうすると、26が渡されたときにループをもう1回まわってしまって、"AA"に変換されてしまう。正しくは"Z"です。
上のメソッドをテストするのが次のコード。
前の投稿で文字コードのことを調べていたのは、このテストでアルファベット26文字分のテストをループを回して済ませたかったからなのでした。
*
逆に”A”を渡すと1を返すメソッドも作ってみる。
作った時期が違うので、メソッド名も引数もローカル変数名もバラバラですな、なかなか恥ずかしい。
そして単体テストがこちら。
こうしてテストで確認できるようにしてあると、確かに安心。
ということで、列番号を渡すと列名を返すメソッドを作ってみる。このメソッドがあると、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); } }
こうしてテストで確認できるようにしてあると、確かに安心。
コメント
コメントを投稿