CONFIGファイル、使ってますか？

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

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

【初めに】
初めて作成したロボットがどんなものだったかは忘れましたが、その時には既に**CONFIGファイル**上で可変要素、今は固定だけど将来変わるであろう要素を管理する方法でした。
色んな現場でロボットを作っていても、**CONFIGファイル**での情報管理は、もう"お作法"と言えるものでした。

令和6年10月2日、総務省 総合通信基盤局電気通信事業部 電気通信技術システム課番号企画室より出された「電気通信番号計画の一部変更等に関する意見募集」から、「電気通信番号計画（令和元年総務省告示第6号）の変更」による今後音声伝送携帯電話番号（070/080/090番号）の枯渇に対しての対策(060番号開放)の素案が示されました。
その際に、市民開発者の方からロボットを改修しなきゃって声を聴くことがありました。あれ、070,080,090を**CONFIGファイル**で管理していれば、音声伝送携帯電話番号としての値に、060を付け加えるだけで対応できるんでは？と問うたら、**CONFIGファイル**ってなんですか？って話になりまして。

このQITTAでは、CONFIGファイルを使用した時のロジックなどを改めてまとめてみようと思います。

- - - 
## １）ロボット仕様
・**CONFIGファイル**上に、音声伝送携帯電話番号（070/080/090番号）を管理するキー、値を定義する。**CONFIGファイル**はMicrosoftのOffice製品であるEXCELファイルにて作成され、そのシート名は"Sheet1"、キー列はＡ列、値列はＢ列とする。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/12812ed0-23bd-dcc6-9ddd-fb87fb466040.png">

・メッセージボックスなどから入力された電話番号の値が携帯電話番号かどうかを、そのキーに対する値と合致するかどうかで判断する。
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/9e2980b4-5b11-66ab-cf8d-78069b97b3d4.png">


・あらゆるシーンで、この判断ロジックが使用できるように考慮する。

- - - 
## ２）ロボットの構成
0. 携帯電話番号の情報をカンマで区切ったその値が定義されている**CONFIGファイル**を読込み、辞書型変数に格納する。
0. 判断ロジックが使用できるように、そのロジックを別xamlに切り出す。その際に引数として、電話番号、**CONFIGファイル**から構築された辞書型変数、判断結果とする。
0. 入力された電話番号が"end"であったら、処理を終了する。英字が含まれるなど、あり得ない電話番号が入力されても携帯電話ではない事とする。

- - - 
## ３）ロボット開発
## ３-0-1）ロボット全体像
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/5cffea42-1e48-a8e0-0a0a-42f946590d24.png">

## ３-0-2）ロボットで使用する変数
| 変数 | 型属性 | 型属性 |
|:-:|:-:|:-|
|dtCONFIG|DataTable|EXCELシートを読み込んだ先の、DataTable型|
|CONFIG|Dictionary(x:String, x:Object)|読み込んだEXCELシートを扱いやすいようにする、辞書型|
|AREACODES|String[]|**CONFIGファイル**に定義されている各携帯電話番号の先頭の値を格納する、配列文字列型|
|in_TelephoneNumber|String|入力された電話番号|
|Terminate|Boolean|処理終了のフラグ|

辞書型を定義するには、「変数」タブの「変数定義の列」の「変数の型」で、「Browse for Types ...」を選択すると、以下のような画面が出ます。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/1395bb42-56dd-9d81-68ff-cc74762b71d1.png">
この画面の「型の名前(N)」で、"DICTIONARY<"と入力して現れる型の候補を選ぶと、更に「キーの型の属性」（左側）、「値の型の属性」（右側）指定できるようになるので、「キーの型の属性」には"String"を、「値の型の属性」には"Object"を指定します（画像は「キーの型の属性」を指定した所）。


配列文字列型を定義するには、「変数」タブの「変数定義の列」の「変数の型」で、「Array of [T]」を選択すると、以下のような画面が出ます。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/2f7757b1-af5a-c894-e6d6-a0d2867b8ba0.png">
この画面の「型を選択」の「T」の部分で、配列にしたい型の属性を指定します。

### ３-1）CONFIGシーケンス
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/1cdc6778-86e2-c779-f669-69dd3714fed8.png">

### ３-1-1）CONFIG 初期化
読み込んだEXCELシートを扱いやすいようにする辞書型の初期化を、「代入」アクティビティを使って行います。
CONFIG ← New Dictionary(Of String, Object)
### ３-1-2）Excel プロセス スコープ
モダンモードでEXCELファイルを扱うのに必要なアクティビティです。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/337f83d9-972b-08d2-aeeb-199e4b9af769.png">
ここでは、シンプルに、「Excelウィンドウを表示：しない」「アラートを表示：しない」ような設定をしました。
### ３-1-2-1）Excel ファイルを使用
実際に扱うEXCELファイルを指定します。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/b2096bd1-08e0-9bbb-d58a-a0bb4ffc5b18.png">
ここでは、シンプルに、「読み取り専用：✓」「ブック パス：（プロセスフォルダ内のCONFIG.xlsx）」ような設定をしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/62ef48b9-b4a0-91a5-4c98-525d7ebf14bd.png)
### ３-1-2-1-1）範囲を読み込み
「Excel ファイルを使用」アクティビティで使用するファイルの、指定されたシート上のデータを、DataTable型に格納します。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/29e70a7d-e54e-58b7-9002-775e63805e7b.png">
「Excel.Sheet("Sheet1").Range("A1")」、「保存先：dtCONFIG」を指定しました。

「Excel.Sheet("Sheet1").Range("A1")」の中にある「Excel」は、「３-1-2-1）Excel ファイルを使用」でのアクティビティの「参照名」で定義されている変数です。この変数には、読み込んだEXCELファイルの情報が格納されています。「Sheet("Sheet1")」はその読み込んだEXCELファイルの情報の中から、シートに関する情報を指定し、「Range("A1")」はそのシート上から読み始めるセル位置を指定します。

### ３-1-3）「繰り返し (データ テーブルの各行)」アクティビティ
読み込んで格納されたDataTable型の変数の各行の値から、辞書型変数に格納します。
### ３-1-3-1）CONFIG 設定
読み込んで格納されたDataTable型の変数の1行の値から辞書型変数への格納を、「代入」アクティビティを使用して行います。
CONFIG(CurrentRow.Item(0).ToString) ← CurrentRow.Item(1)
左辺は、辞書型変数(辞書のキー：1行の先頭列、すなわちA列）
右辺は、1行の先頭列の右となり、すなわちB列
となります。
### ３-1-3-99）処理結果
以下のEXCELシート上の情報が、
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/12812ed0-23bd-dcc6-9ddd-fb87fb466040.png">
辞書型変数として、以下のようになります。
|キー|値|
|:-:|:-:|
|MOBILE|070,090|

基本的に、辞書型変数から値を取り出すには、**辞書型変数("キー")**とします。"キー"部分はString変数でも指定可能です。

### ３-2）AREACODES シーケンス
ここでは、EXCELファイル上にカンマで区切った携帯電話の定義が辞書型に格納され、その辞書型からその定義を参照、配列文字列型に変換します。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/f0d6c140-f6a7-ed32-2382-3abb3049a1ec.png">
左辺は、配列文字列型
右辺は、
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/2e908094-6db1-30fb-ede4-63f524cc4bb3.png">
となります。
### ３-2-1）右辺解説
0. 辞書型変数であるCONFIGは、キーはString型、値はObject型で定義されていますので、参照した値は、Object型になります
0. それを一度文字列型に変換し(.ToString)します(L.1)
0. EXCELのセルのセル内改行を除去するため、CrコードをString.Emprtに置換(.Replace)し、LfコードをTabコードに置換(.Replace)します(L.2,3)
0. カンマで区切る設定ですが、念のために、ピリオド、コロン、セミコロンをTabコードに置換(.Replace)します(L.4~7)
0. 文字列を、Tabコードで分割(.Split)します(L.8)
0. その配列の中から、LINQ(.Where)を使って、空白でないものだけを抽出します(L.9)
0. その抽出した結果を、改めて配列に変換(.ToArray)します(L.10)
### ３-2-99）処理結果
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/9876d1d3-7a39-d7b0-da13-1085f3f91451.png">

### ３-3）「繰り返し (後判定)」アクティビティ
「入力ダイアログ」アクティビティから入力された"電話番号"を、判定するXAMLに渡して判断し、その結果を「メッセージボックス」アクティビティにて表示する。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/02a14859-d33c-50b9-a89d-8fa7104b5e7e.png">
条件として、Terminateと言う変数の値が、Trueでない間、内包するロジックを実行します。
### ３-3-1）「入力ダイアログ」アクティビティ
ロボット上に入力を促すダイアログを表示します。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/2719378d-6dba-94d9-3756-46cddbaa177a.png">
ここでは、「タイトル："電話番号を入れてください"」、「ラベル："終了する時は、""END""と入力してください"」、「結果：in_TelephoneNumber」を指定しました。
### ３-3-2）「ワークフロー ファイルを呼び出し」アクティビティ
「入力ダイアログ」アクティビティから入力された値と、AREACODES シーケンスで加工された配列文字列の値と、判断結果を受け取る変数を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/e586cb18-8ca4-87f9-010b-2b1118fee545.png)
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/fc2e763d-02c7-3bea-b7a5-f9d5dd4825df.png">
### ３-3-3）終了判定
「入力ダイアログ」アクティビティから入力された値が"END"だったら、LOOPから抜け出せる条件を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/4f47bba9-9345-0ba9-90d2-ebf92e455fe6.png)
左辺は、Boolean型
右辺は、StrConv(in_TelephoneNumber, VbStrConv.Uppercase).Equals("END")
とし、入力された値を大文字に変換してから、その値が"END"と一致するか
を「代入」アクティビティを使用し、行っています。
### ３-3-4）終了判定か？ (if)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/afce104c-a07d-73eb-c48c-3a70158521f9.png)
終了でなければ、「メッセージボックス」アクティビティを使用して、以下の情報を表示させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/acf698ab-6d6a-0a41-bd38-e606b1de12a1.png)
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/dec9485b-9729-ae09-0fc8-c41f19104e96.png">
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/1160ce30-eafc-41f5-c11e-9bcde8758ce9.png">
### ３-4）mobile_phone_Checker_D.xaml
とてもxamlに切り出すレベルの規模ではないのですが...
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/f0018873-c153-f15a-d59d-41febfae2d20.png">
### ３-4-1）携帯電話 判定
左辺は、Boolean型
右辺は、AREACODES.Contains(TelephoneNumber.Substring(0,3))
とし、入力された値の先頭から3文字が、AREACODESに含まれているかをTrue/Falseで返却する。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/47135849-8eba-23df-6538-a374141a5a0a.png">
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/406e5f61-02e6-5d1f-77c0-612f536aebfe.png">
- - - 
## ４）060が携帯電話番号として採用可決されたら...
### ４-1）**CONFIGファイル**での対応
【従来のCONFIG定義】
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/12812ed0-23bd-dcc6-9ddd-fb87fb466040.png">
↓
【対応後のCONFIG定義】 ... ３-2-1）右辺解説で解説したように、カンマのみならず、セル内改行、ピリオド、コロン、セミコロンで区切っても改造仕様を満たす
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/3d750616-1cab-82a9-2edf-564678ae4917.png">

### ４-2）カンマ以外での区切り文字まで救済するかの是非
仕様としては、**２）ロボットの構成**で説明したように"カンマで区切る"ことだけを対応すべきでしょうが、EXCEL上での見やすさを考慮してセル内改行で設定してしまう場合もあると思います。
その場合に、
1. 予期せぬ異常終了とさせる
2. 予期せぬ異常終了を、Try～Catchで捕捉させる
事になりますが、それらが発生した場合にどう対処するのかを調査、対応するコストを考慮したら、カンマ以外での区切り文字まで救済するのも一案かと思っています。

- - - 

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

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

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