チャレンジ！EXCELの列数字から、列英字を取得する

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

【初めに】
EXCEL Applicarion Scope配下で使用するシート上のデータを読み書きするアクティビティなどは、その対象範囲を「列英字＋行位置（：列英字＋行位置）」で指定していきます。

列英字は、例えばCONFIG.xlsxに保有して、固定的に指定した値を使用するなんて事も出来ますが、列位置が不定で...なんて場合は、数値から列英字を変換、取得しなければなりません。

その方法は、開発者の中で決まった方法はないでしょう。それをちょっとまとめておきましょう！更に、 **新しく** 取得する方法を発見しましたので、それも併せて投稿しようと思います。

- - - 
## １）文字列型配列
一番簡単な、安易な方法かと思います。
文字列配列を定義し、そこに、事前に取得した列英字群を規定値として設定しておき、配列の参照の方法で取得すると言うものです。
【変数の定義】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/a9ed155f-b915-2c7d-ddbf-5921832c61a0.png)
【定義から参照】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/13661435-ba0f-49fa-0c8f-0d077ae33956.png)
【メリット】
・兎に角簡単に定義、参照できる。
・それこそ２６列（A列~Z列)位だったら、手っ取り早い
【デメリット】
・列対象範囲が大きくなると、列英字群を作成するのに手間が掛かる。
・16384列までの定義が、文字列配列の許容サイズを超えてしまう。

- - - 
## ２）List型
文字列型配列だと、16384列までの定義が出来ないので、この列英字を外部ファイルにして置き、読み込んでから、List型変数へ設定しておき、List型の参照の方法で取得すると言うものです。
【変数への設定】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/4b46695c-8aee-5015-cf99-717a69bd9a29.png)
【定義から参照】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/be6e41f0-b777-da52-86d0-a5c22109de3a.png)
【メリット】
・16384列までの定義でも、参照できる。
【デメリット】
・列対象範囲が大きくなると、列英字群を作成するのに手間が掛かる。

- - - 
## ３）計算方式
外部に定義するのも大変なので、列数値から列英字を計算させてしまおうという方法。
【変数への設定】
なし
【計算式】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/6e07c72e-c8cc-e7ac-15f8-694e305a3900.png)
【メリット】
・事前に列英字群を定義しなくてもよい
【デメリット】
・この計算式を探すのに手間（ですので、この投稿が役に立つ！）

- - - 
## ４）ExcelWorkbookScope型
ExcelWorkbookScopeは、「EXCEL Application Scope」アクティビティ内部で使用する、EXCEL自身の変数で、様々な情報が格納されています（これについてはもうちょっと調査してから投稿します）
EXCEL-VBAを嗜む方でしたら、ExcelWorkbookScopeが、Workbook->workSheet->Range->Cellsという関連に似ていそうだって事は想像できるかと思います。そこでやってみました！
【計算式】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/236250af-a875-5309-3c1f-6c230b259606.png)

代入アクティビティの右辺```ExcelWorkbookScope.CurrentWorksheet.Range(ExcelWorkbookScope.CurrentWorksheet.Cells(1, ix), ExcelWorkbookScope.CurrentWorksheet.Cells(1, ix)).Address(True, False).Split("$"c)(0)```

説明します。
ExcelWorkbookScopeの.CurrentWorkSheetで現在のシートを参照可能とし、そのシート上の範囲を、.Range(.Cells(行,列),.Cells(行,列))で取得。
それをAddress(True, False)として取得すると、「A\\$1」の形式のセルアドレス値が取得できるので、それを"$"でSplitし、Splitした配列の0番目を列数字に対応する列英字とします。
【メリット】
・行数字、列数字から、アクティビティで使う為のレンジ値として取得できる！
【デメリット】
・EXCEL-VBAだと、.RANGEではなく、.CELLS(行,列)でアドレスが取得できるが、.RANGE(.CELLS(行,列), .CELLS(行,列))でないと、取得できない。
⇒1セルの場合は、行数字、列数字に同じ値を設定する。
・どうやら、最初の.CurrentWorkSheetはNull値であるので、.CurrentWorkSheetに何らかのシートを割り当ててあげなければならない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/a699b3de-f4a2-d545-38eb-bb58904de1b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/5439c2d4-ad15-34c9-b375-15b9193c81d6.png)
最左端のシートを割り当てる例。Boolean値がFalseなのは、シートが無かったら挿入するかのモードであり、今回の例では最左端のシートが無いことがあり得ないので、Falseとしている。



- - - 
## 性能測定
今回、1列～9000列までの列英字を取得する時間を3回計測してみました。
その平均値を下表にまとめます。
| 方法 | 準備(秒.ミリ秒) | 結果(秒.ミリ秒)|
|:-----------|:------------:|:------------:|
| 文字列型配列|-|0.0439|
| List型|0.0165|0.0359|
| 計算方式|-|0.2418|
| ExcelWorkbookScope型 |2.1493|38.8503|

## 【まとめ】
・対象とする列数字の範囲が小さければ、文字列型配列を定義して、それを参照する方が簡単。ただ、各所にその定義をするのであれば、共通部品化するのがいい。
・対象とする列数字の範囲をEXCELシートの列範囲をすべてカヴァーする必要があるのであれば、その値を外部ファイルに保有し、加工処理する必要がある。いっそ、計算方式の方が楽。ただ、これも各所で列英字を求める要件があるのであれば、共通部品化するのがいい。
・EXCELの事はExcelWorkbookScopeを利用して求める方法は、事前に.SetSheetをしなくてはならないし、その割に計算方式の160倍の時間が掛かっているので、あまりお勧めしない。

- - - 

## おわりに
いかがでした？

EXCELの事はExcelWorkbookScopeを利用して、しかも高速に求められるであろうと思って始めたチャレンジでしたが、期待外れでした。解法に向けて、いろんなアプローチを試してみて、それは尊いものと割り切って、開発に勤しみましょう！

今回も読んでいただきありがとうございました！
是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！