WORD VBA で簡単なツールを作成する手順（文書の数字文字列変換）

# 1. はじめに
この記事では、マクロ（VBA）は多少触っているレベルの方を対象にして、フォームを使った**ツールの作り方**と**配布方法**までの手順を書いておきます。

以下、WORD VBAを使って、次のような簡素な文書変換ツールの作り方を順を追いながら紹介していきます。
順を追って作業していただければ（読んでいただければ）、おおよその流れがわかるかと思います。
![2020-10-06 014556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/31ff200a-6b5c-829b-3f3d-dd5770680696.png)

## 1-1. 作成するツールの概要（使い方）
ここで作成するのはどういうツールかを簡単に説明しておきます。

**①アイコンからフォームを表示**
フォームはツールバーのアイコンをクリックして立ち上げます（赤枠部分）。
![2020-10-06 014908.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/40619b07-0242-7336-ef95-8890ae88db2f.png)
**②数字部分の自動マーキング**
`数字部分のマーキング`ボタンを押すことで、変換の対象となる数字部分が自動的にマーキングされます。
![2020-10-06 015108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ed60bfde-6fba-4e21-c651-d6bf80ca6546.png)
**③変換をしない数字についてマーキングを解除する**
変換したくない数字は、マーキングを解除することで変換を回避できます。
マーキングは、WORDのメニューからでも解除できますし、ツールの`選択部分のマーキングをクリア`ボタンを使うことでも解除できます。

**④表記種別を選択して変換を実行**
マーキング部分の数字を一括変換するには、`マーキング部分の数字変換を実行`ボタンを押すことで、変換を実行できます。
![2020-10-06 015513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/17a37692-a81c-b8d1-88c7-af4c2806b173.png)
数字変換の種類は、コンボボックスから算用数字、漢数字など4つのパターンを選択することができます。
![2020-10-06 015633.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/00e73c6e-8942-e861-0ecd-63294f780f43.png)
**＜変換種別一覧＞**

|種別|表記例|
|---|---|
|算用数字|538,000,000|
|漢数字1|五億三千八百万|
|漢数字2|五億三八〇〇万|
|数字・漢字混合|5億3800万|

## 1-2. フォームとモジュールの新規作成
下準備として、使用するフォーム画面とモジュールの新規作成を行います。

まず、新規WORDファイル（拡張子は`.docm`としてください）を作って、VBAの画面を開きます。
ここでは`SampleTool.docm`というファイル名にしました。

そして、VBAの画面のメニュー「挿入」から、「ユーザーフォーム」を２つ、「標準モジュール」を１つ作成します。
![2020-10-04 161205.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/8b7919af-8e74-dc18-e8d8-644db4438469.png)
作成が完了すると<font color="Red">**赤枠**</font>部分のようにUserFormが２つ、Moduleが１つ表示されていると思います。
なお、<font color="blue">**青枠**</font>で囲んだ部分は、コード表示（左側）とフォーム表示（右側）の切り替えボタンとなります。
![2020-10-04 161426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/e8def0fb-c2fe-853d-7451-ffb00225a5c7.png)
フォーム名、モジュール名はこのままでも構わないのですが、上図の<font color="green">**緑枠**</font>部分を変更することでモジュール名を変更することができます。
ここでは、次のように名称を変更しておきます。

|変更前|変更後|区分|
|---|---|---|
|UserForm1|ConvForm|フォーム（クラスモジュール）|
|UserForm2|ProgressForm|フォーム（クラスモジュール）|
|Module1|ConvNumModule|標準モジュール|

2つのフォーム（ConvForm、ProgressForm）には、フォーム操作に関係あるコードのみ記載します。
メインとなるコードは、標準モジュール（ConvNumModule）の方に書いていきます。

では、早速、標準モジュールに次のコードを記載します。

```vb
'フォームを開く
Sub OpenForm()
    ConvForm.Show vbModeless
End Sub
```

以上のコードで、フォームを開くことができます。
単純に、`フォーム名.Show`（ConvForm.Show）だけでも、フォームを開くことができます。
しかし、そのままでは「[モーダル](https://wa3.i-3-i.info/word11432.html)表示」となり、フォームを開いている間は他の操作ができなくなってしまいますので、末尾に`vbModeless`と記載して、フォーム表示中も文書の編集ができる「モードレス表示」で開くようにします。
詳しくは、公式ドキュメントの[Showメソッド](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/show-method)を参照してください。

それでは、コードを記載した部分（下図の<font color="Red">**赤枠**</font>部分）のどこかにカーソルを置いて、<font color="blue">**青丸**</font>部分の実行ボタンを押してみてください。
![2020-10-03 210041.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/97ef7c23-ecdf-6cfe-7be0-ea9e087be8fb.png)
次のようにフォームが表示されれば成功です。
![2020-10-03 210933.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/b33a1ab2-2886-e0bb-22d3-ef13a6bada2a.png)

なお、普通に「開発」メニューの「マクロ」から次の画面を開いて「OpenForm」を実行しても結果は同じです。
![2020-10-05 234719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ccf0455c-f5d8-8488-84a6-b68b6cf20e70.png)

# 2. メインフォームの作成（クラスモジュール）
ここでは、ユーザーが操作を行うための次のようなフォームを作成していきます。
![2020-10-04 153540.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/c8ed6bfa-7900-fd18-5120-1672654833a8.png)
## 2-1. フォーム画面の編集
それでは、フォームの画面を作っていきます。
図の青枠の「ConvForm」をダブルクリックするとフォームの編集画面が表示されます。
そして、プロパティのCaptionにある「UserForm1」を「数字変換ツール」と書き換えてください。すると、フォームのバーのところに「数字変換ツール」と表示されます。タイトルなので別の名前でも構いません。
![2020-10-04 160536.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2cc0ff97-a4c9-8523-1ede-6924ab21a3fd.png)
作成にあたって、画面下の方にある「イミディエイトウィンドウ」と「ツールボックス」（緑枠で囲んだ2つ）を使いますので、これが表示されていない場合は、メニューの「表示」から、この2つのウィンドウを表示させておいてください（ツールボックスはフォームを選択している時にのみ表示されますのでご注意ください。）。

### 2-1-1. ボタンの作成

次に、ツールボックスの赤枠部分にある「コマンドボタン」をクリックして、フォームの左上あたりをクリックしてください。
そうするとボタンが作成されます（図の青枠部分）。
![2020-10-04 160146.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/20d58cd2-c49f-71cd-df36-90570b10c87e.png)
続いて、プロパティウィンドウのオブジェクト名を「HighlightNumBtn」に、Captionを「数字部分の自動マーキング」と変更してください（赤枠部分）。
そして、青枠部分のボタンの幅を適当に広げて、文字全体が表示されるようにしてください。
![2020-10-04 155925.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/c1820965-3f2e-fef6-56e3-4201e6e3779b.png)
なお、ボタンの大きさは、プロパティウィンドウの項目別タブから数値で指定することもできます（青枠部分）。
![2020-10-03 225948.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/9e22927e-ee39-11ad-25aa-8c26847e6262.png)
言うまでもないかもしれませんが、各数値の意味は次のとおりです。

|項目|内容|
|---|---|
|Height|ボタンの高さ|
|Left|ボタンの水平位置|
|Top|ボタンの垂直位置|
|Width|ボタンの横幅|

同様に、ボタンを更に2つ作成します。
![2020-10-04 155706.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/f39f9732-fd97-e140-eb91-e64d1d914691.png)
作成するボタンの各項目は、次のように設定してください（HeightとWidthは目安ですのでご参考までに）。

|オブジェクト名|Caption|Height|Width|
|---|---|---|---|
|CrearHighlightBtn|マーキング全てをクリア|18|180|
|CrearHighlightOnSelectionBtn|選択部分のマーキングをクリア|18|180|

### 2-1-2. フレームの作成
見た目を整えるために、フレームを使用してみます。
これは、特に作らなくても動作には一切影響しませんので、不要な方は飛ばしてください。

最初に、フォームを縦長に大きくしておきます。
適当で良いのですが、私の手元では、Height=342、Width=240としています。

そして、ツールボックスの「フレーム」（赤枠部分）を選択して、作成済みの3つのコマンドボタンの下あたりをクリックしてフレームを作成します。
![2020-10-04 155359.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/893345f9-3db2-f7ba-2665-500ba261d60e.png)
そして、作成済みの3つのボタンを、作成したフレームの上に、ドラッグ&ドロップ（または切り取って貼り付け）で乗せていきます。
これで、フレームとコマンドボタンが一体化されるので、フレームを動かせばコマンドボタンも一緒に動くようになります。
![2020-10-03 235729.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2d1bc302-16f9-7673-f4e0-dbbd2519f981.png)
フレームの位置、大きさを次のように調整して、プロパティウィンドウのCaptionを「数字マーキング」としてください。
![2020-10-04 154646.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/cbc6e9a2-05f5-61e7-7b37-819a63690adf.png)
参考までに、私の手元では次のように、フレームの高さは108、幅は204となっています。
![2020-10-04 001737.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/f7e57450-24c1-c8a7-dc1d-31636b1d7fed.png)
### 2-1-3. ラベルの作成
次にラベルの作成ですが、これも、見た目を整えるためのもので、プログラムの動作には関係しません。

ツールボックスの「ラベル」（赤枠部分）を選択して、フォームの上の方（青枠部分）をクリックしてラベルを作成します。
プロパティウィンドウは、緑枠のところ、Captionを「数字部分をマーキングした上で変換を実行してください」と記載して、TextAlignは「2 - fmTextAlignCenter」を選択します。
![2020-10-04 154255.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/b61e7863-bdd3-581f-6c4d-9684d56e1950.png)
ラベルの位置・大きさは適当で構いませんが、私の手元では次のようになっています。
![2020-10-04 003953.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0af6882b-19c8-7ab4-1fd7-40d7a9f0bf7e.png)
### 2-1-4. 追加のコントロールを作成
続いて、今までと同様の方法で、赤枠部分のように、フレーム、ラベル、コマンドボタンを作成します。
作成順に決まりはありませんが、先にフレームを作成して、その上に、ラベル、コマンドボタンを置いていく方が作りやすいと思います。
![2020-10-04 102248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/8ad63ada-f426-85b9-6369-9e2fc2b4e7db.png)
各コントロールの設定は、次のとおりです。

**＜フレーム＞**

|オブジェクト名|Caption|Height|Left|Top|Width|
|---|---|---|---|---|---|
|(変更不要)|漢数字または算用数字変換|126|12|168|204|

**＜ラベル＞**

|オブジェクト名|Caption|TextAlign|Height|Left|Top|Width|
|---|---|---|---|---|---|---|
|(変更不要)|数字変換の種類を選択してください|1-fmTextAlignLeft|12|12|12|180|
|SelectLabel|表記例：|1-fmTextAlignLeft|12|12|36|180|
※TextAlignは初期設定のままとなります（左寄せ）。
※2つ目のラベルはプログラムで操作しますので、オブジェクト名を`SelectLabel`としておく必要があります。

**＜コマンドボタン＞**

|オブジェクト名|Caption|Height|Left|Top|Width|
|---|---|---|---|---|---|
|ConvKan2NumBtn|マーキング部分の数字変換を実行|24|12|84|180|

### 2-1-5. コンボボックスの作成
さて、次はコンボボックスの作成です。

ツールボックスの「コンボボックス」（赤枠部分）を選択して、フォーム中の青枠部分のようにコンボボックスを作成します。
プロパティウィンドウは、緑枠の「オブジェクト名」を「SelectCmb」と記載します。
![2020-10-04 110511.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/f35523a2-5a7e-b438-bf71-74e137b2c240.png)
位置や大きさは適当で構いませんが、私の手元では次のようになってます。
![2020-10-04 111149.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ce1a1572-0ec1-fdbc-ce54-0b81c8880627.png)

### 2-1-6. フォームの表示とタブ順の調整
では、フォームが出来上がっているか確認してみます。
冒頭でConvNumModule（標準モジュール）に作成したフォームを開くためのプロシージャ`Sub OpenForm`を実行してフォームを開きます。
![2020-10-04 112328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0f310c30-fca9-5d9a-4aa9-9104f0f93c86.png)
まだ、コードを記述していないので、ボタンを押しても反応はありませんし、コンボボックスの右側の矢印ボタンを押しても何も表示されません。

`Tab`キーを押すと、4つのボタンと1つのコンボボックスにつき、コントロールを作成した順にフォーカスが移っていくと思います。
これを上から順に移行させるためには、各コントロールのプロパティにある項目`TabIndex`（下図赤枠部分）の数値を変更してTabキーの順序を変更します。
![2020-10-04 113000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/fec0956f-3f92-529a-cb53-eba938efbbe1.png)
自分で数値を打ち込みながら、上手く順番に並ぶように調整してみてください。
タブ順は、プログラムの実行には関係しませんので、こだわりがなければ順序を修正しなくとも大丈夫です。

## 2-2. フォームのソースコード作成
### 2-2-1.【参考】メインフォームのソースコード（完成形）
とりあえず、コピペしたいという方もいると思いますので、先に完成後のメインフォームのソースコードを貼っておきます。
次の項から、１つずつ取り上げて説明していきます。

```vb
Option Explicit

Private Sub UserForm_Initialize()
    SelectCmb.AddItem "算用数字"
    SelectCmb.AddItem "漢数字1（十百千を含む）"
    SelectCmb.AddItem "漢数字2（十百千を含まない）"
    SelectCmb.AddItem "数字・漢字混合"
    SelectCmb.ListIndex = 0
End Sub

Private Sub HighlightNumBtn_Click()
    Call HighlightNum
End Sub

Private Sub CrearHighlightBtn_Click()
    Call CrearHighlight
End Sub

Private Sub CrearHighlightOnSelectionBtn_Click()
    Call CrearHighlightOnSelection
End Sub

Private Sub SelectCmb_Change()
    Select Case SelectCmb.ListIndex
        Case 0
            SelectLabel.Caption = "表記例：538,000,000"
        Case 1
            SelectLabel.Caption = "表記例：五億三千八百万"
        Case 2
            SelectLabel.Caption = "表記例：五億三八〇〇万"
        Case 3
            SelectLabel.Caption = "表記例：5億3800万"
        Case Else
            SelectLabel.Caption = ""
    End Select
End Sub

Private Sub ConvKan2NumBtn_Click()
    Call ConvNum(SelectCmb.ListIndex)
End Sub
```

### 2-2-2. コマンドボタンのソースコード
作成したコマンドボタンをクリックすることで、処理が走るように（イベントが発火するように）設定していきます。

VBA画面のフォーム中の一番上のボタン（赤枠部分）をダブルクリックしてください。
![2020-10-04 114425.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ce8091e5-4180-e9cb-a745-6f6a6a398308.png)
そうすると、次のように自動でコードが作成されます。
![2020-10-04 115757.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/5855e6c8-867e-31f2-194d-c09e89d8ac30.png)
プロシージャの名称部分の前半`HighlightNumBtn`はコントローラー名（コマンドボタンのオブジェクト名）であり、後半の`Click`は処理内容を表しています。

ボタンがクリックされると、この`Private Sub HighlightNumBtn_Click`というプロシージャに記載されている処理が実行されることになります。

なお、これ以外のプロシージャ（`Private Sub UserForm_Click`など）が勝手に作成されている場合もあると思います。
そのような不要なプロシージャは消してしまって問題ありません。

具体的な処理内容は、後でコードを作成しますので、ここでは、次のようなテストコードを書いておきます。

```vb
Private Sub HighlightNumBtn_Click()
    Debug.Print "ボタンがクリックされました"
End Sub
```

`Debug.Print [値]`と記述することで、イミディエイトウィンドウに`[値]`を表示することができます。

それでは、もう一度、ConvNumModule（標準モジュール）から`Sub OpenForm`を実行してフォームを開いて、最初のボタン「数字部分の自動マーキング」を押してみてください。
イミディエイトウィンドウに「ボタンがクリックされました」と表示されていれば成功です。
![2020-10-04 120835.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/f8c40b6a-a485-a3fd-d434-69d3682e53ff.png)
### 2-2-3. コンボボックスのソースコード
#### 2-2-3-1. リストの初期化
現在のコンボボックスは、枠だけ設定している状態で、中身のリストは設定されていません。
コンボボックスの初期値として、4つの選択肢を設定するコードを書くと次のようになります。
（Withステートメントを使えばもう少しコードがすっきりしますが、分かりやすさ重視のため、ここでは使用しません。）

```vb
'コンボボックスに初期値を設定する
Private Sub UserForm_Initialize()
    SelectCmb.AddItem "算用数字"
    SelectCmb.AddItem "漢数字1（十百千を含む）"
    SelectCmb.AddItem "漢数字2（十百千を含まない）"
    SelectCmb.AddItem "数字・漢字混合"
    SelectCmb.ListIndex = 0
End Sub
```

プロシージャ名の`UserForm_Initialize`は、このフォーム（ここではConvForm）の、初期化（initialize）を行うという意味になります。
このプロシージャの処理は、フォームが表示されるまでの間に実行されます（詳しくは「[Initializeイベント](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/initialize-event)」を参照）。

そして、コンボボックスのリストの中身は、`[コンボボックス名].AddItem [リスト項目]`という構文で追加していくことができます。
コンボボックスの名称（オブジェクト名）を`SelectCmb`としていましたので、`SelectCmb.AddItem "算用数字"`という振り合いで書けば、`"算用数字"`というリストが追加されることになります。

また、リストの項目を追加する度に、0, 1, 2, 3 ... の順で、自動的にインデックスが振られていきます。
上のコードの場合、`"数字・漢字混合"`というリスト項目には、インデックス番号として`3`が振られることになります。

インデックス番号は`[コンボボックス名].ListIndex`という構文で取得できます。
最後の行の`SelectCmb.ListIndex = 0`は、フォームを開いた際には、インデックス`0`のリスト項目（`"算用数字"`）を表示するように指定しているものです。

フォームを立ち上げると、次のようにリストボックスの選択ができるようになっていることが分かると思います。
![2020-10-04 134647.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/dead09a5-9f78-c535-d4a6-5c5a70672247.png)

なお、`Private Sub UserForm_Initialize()`というコードは、ベタ打ちしても構いませんが、次の方法で簡単に作成することができます。

下の図の赤枠部分の右側のボタンをクリックすると、関係するコントローラーやオブジェクトの一覧が表示されますので、UserFormを選択します。
![2020-10-04 145929.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ae5192cf-769f-8120-c2b6-7a755035e611.png)
次に、下図の赤枠部分の右側のボタンをクリックすると、作成することができるイベントの一覧が表示されますので、`Initialize`を選択します。
![2020-10-04 135738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/7c68cdd3-8cb3-d631-7993-2cb74576a57f.png)
すると、下図の赤枠部分に、上記コードと同じ`Private Sub UserForm_Initialize()`プロシージャが作成されますので、この中に必要な処理を書けば良いということになります。
なお、緑枠の部分のコードも勝手に生成されてしまうので、これは削除してください。
![2020-10-04 140359.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2428dc36-6819-7115-3355-a7480f0ac79b.png)
これを使えば、clickイベントでもchangeイベント（次項で使用します）でも、コードの自動生成が可能です。

#### 2-2-3-2. リスト選択に連動する処理
コンボボックスのすぐ上に、`表記例：`というラベルがあります。
このラベルを、コンボボックスの選択した内容によって変化させるようにします。
コードは、次のようになります。

```vb
'コンボボックスの選択により表示するラベルを変更する
Private Sub SelectCmb_Change()
    Select Case SelectCmb.ListIndex
        Case 0
            SelectLabel.Caption = "表記例：538,000,000"
        Case 1
            SelectLabel.Caption = "表記例：五億三千八百万"
        Case 2
            SelectLabel.Caption = "表記例：五億三八〇〇万"
        Case 3
            SelectLabel.Caption = "表記例：5億3800万"
        Case Else
            SelectLabel.Caption = ""
    End Select
End Sub
```

プロシージャ名`SelectCmb_Change`の前半は、コンボボックスの名称（オブジェクト名）です。後半の`change`はイベント名です。
これは、コンボボックスの選択が変わる度に実行されるプロシージャとなります（詳しくは「[Changeイベント](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/change-event)」を参照してください）。

コードはベタ打ちしても構いませんが、VBA画面に表示されているフォームのコンボボックスをダブルクリックすると、空のプロシージャが自動で生成されますので試してみてください。

[Select Case文](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/select-case-statement)でケース分けする値には、コンボボックスのインデックス（先ほど説明した`SelectCmb.ListIndex`）を使用しています。
インデックス番号ごとにラベル（ラベル名：`SelectLabel`）に表示する文言を指定するだけの単純なコードです。
なお、ラベルの文言は、`[ラベル名].Caption`という形で呼び出して、値の取得・変更をすることができます。

フォームを立ち上げてコンボボックスを操作すると、選択が変わる度に`表記例：`のラベル表示が変化することが分かると思います。
![2020-10-04 145624.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/e5dca94b-92ec-9709-1c65-83c96f000f57.png)

以上、フォーム（クラスモジュール）のソースコードの基本的なところを記載していきました。
現時点では、次のようなソースコードになっていると思います。
![2020-10-04 150448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/053bed75-5fbd-7524-89c7-ea825deda30a.png)
フォームのソースコード作成については、一旦ここまでにします。
残りは、標準モジュールで必要なプロシージャを作成後に、追加していきます。

# 3. プログレスバーの作成（クラスモジュール）
ここでは、もう一つのフォーム`ProgressForm`を使ってプログレスバーを作成していきます。

## 3-1. プログレスバーを使用する前準備
まず、プロパティの`Caption`（赤枠部分）を「処理中」と変更してください（別の言葉でも構いません）。
次に、ツールボックスにプログレスバーのアイコンを表示させます（デフォルトではプログレスバーのアイコンはありません）。
ツールボックスの青枠部分を右クリックするとメニューが表示されますので、「その他のコントロール」を選択してください。
![2020-10-04 163312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/793efcfd-e2af-a0f4-b0f9-5d40d9a4d83a.png)
次のような「コントロールの追加」のウィンドウが表示されますので、「利用可能なコントロール」の中から、「Microsoft ProgressBar Control, version ...」を探してチェックを入れてOKボタンを押します。
![2020-10-04 164528.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0067a7f7-07e8-e2e3-d3ef-f6ddfb4515a2.png)
するとツールボックスの右下にプログレスバーのアイコンが表示されます。
![2020-10-04 164755.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/8d591ede-c64d-edb9-4d4d-c7bece62dba9.png)
## 3-2. プログレスバーの作成
ツールボックスの赤枠部分にある「プログレスバー」をクリックして、青枠部分のような形でプログレスバーを作成します。
緑枠部分のプログレスバーのオブジェクト名は、デフォルトの「ProgressBar1」から「Bar1」に変更しておきます。
あわせて、フォームの高さも小さく調整しておきます（私の手元ではHeight=80です）。
![2020-10-04 172303.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/e869f17b-9587-4fa2-38f6-12e9b6616fda.png)
以上で、`ProgressForm`の編集は終わりです。ソースコードは、標準モジュール（`ConvNumModule`）の方に書きますので、このフォーム（クラスモジュール）ではソースコードの記述は不要です。

# 4. 標準モジュールのソースコード作成
標準モジュールのコード内容の説明は、多少割愛しつつ、ツール作成に関係あるところを中心に記しておきます。
## 4-1. 【参考】標準モジュールのソースコード（完成形）
これも、先に最終形のソースコードを貼っておきます。コードは約200行です。
後から、１つずつ概要を説明していきます。

```vb
Option Explicit

Const numChr = "〇一二三四五六七八九十百千万億兆0123456789０１２３４５６７８９,"

'フォームを開く
Sub OpenForm()
    ConvForm.Show vbModeless
End Sub

'数字部分のマーキング処理をするプロシージャ
Sub HighlightNum()
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("文書中の数字部分を一括してマーキングします" & vbCrLf & "このまま処理を続行しますか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
    
    ProgressForm.Show vbModeless 'プログレスバーを表示
    With ActiveDocument
        Dim i As Long: i = 0 '指定しなくとも初期値は0となる
        Do While i < .Content.End
            If InStr(numChr, .Range(i, i + 1).text) > 0 Then
                .Range(i, i + 1).HighlightColorIndex = wdYellow
            End If
            i = i + 1
            ProgressForm.Bar1.Value = (i / .Content.End) * 100 'プログレスバーの数値変更
        Loop
    End With
    Call ClearHighlightOnField '計算フィールドのマーキングを解除する
    Unload ProgressForm 'プログレスバーを非表示
End Sub

'計算フィールドのマーキングを解除するプロシージャ
Sub ClearHighlightOnField()
    Dim fld As Field
    Dim rng As Range: Set rng = Selection.Range '選択範囲（Range）の初期状態を記録
    For Each fld In ActiveDocument.Fields
        fld.Select 'Rangeプロパティを持たないため範囲選択（Select）を行う
        Selection.Range.HighlightColorIndex = wdNoHighlight 'SelectionオブジェクトのRengeプロパティから領域を取得する
    Next
    rng.Select: Set rng = Nothing '選択範囲（Range）を初期状態に戻す
End Sub

'全マーキングを解除するプロシージャ
Sub CrearHighlight()
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("文書中の全てのマーキングをクリアしてよいですか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
    
    ActiveDocument.Content.HighlightColorIndex = wdNoHighlight '文書全体のマーキングをクリア
End Sub

'選択部分のマーキングを解除するプロシージャ
Sub CrearHighlightOnSelection()
    Selection.Range.HighlightColorIndex = wdNoHighlight
End Sub

'文書中のマーキングされた数字を変換するプロシージャ
Sub ConvNum(Optional typ As Long = 0)
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("マーキングされている数字の変換を実行します" & vbCrLf & "このまま処理を続行しますか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
    
    Dim i As Long
    Dim s As Long '数字部分のスタート位置を記録する変数
    Dim rng As Range
    Dim numFlg As Boolean: numFlg = False '数字の場合にTrueとするフラグ
    
    ProgressForm.Show vbModeless 'プログレスバーを表示
    With ActiveDocument 'ActiveDocumentの記述を省略するステートメント
        Do While i < .Content.End
            If InStr(numChr, .Range(i, i + 1).text) > 0 Then '文字が数字であるか否かの判定
                If numFlg = False Then
                    s = i '数字が出現したスタート位置を記録
                    numFlg = True '数字部分に入ったためTrueに変更
                End If
            Else
                If numFlg = True Then 'numFlgがTrueであれば直前までが数字であったということ
                    Set rng = .Range(s, i) '数字部分のRangeを変数rngに設定
                    If rng.HighlightColorIndex <> wdNoHighlight Then
                        If typ = 0 Then
                            rng.text = Format(ConvKan2Num(Replace(rng.text, ",", "")), "###,###") 'ConvKan2Num関数を使って漢数字を算用数字に変換
                        Else
                            rng.text = ConvNum2Kan(ConvKan2Num(Replace(rng.text, ",", "")), typ) 'ConvNum2Kan関数を使って算用数字を漢数字に変換
                        End If
                        If .TrackRevisions Then '変更履歴機能がオンかオフか
                            i = i + Len(rng.text) '変換後の数字の末尾にiを再設定（文字数が変わるため）
                        Else
                            i = s + Len(rng.text) '変換後の数字の末尾にiを再設定（文字数が変わるため）
                        End If
                    End If
                    numFlg = False
                End If
            End If
            i = i + 1
            ProgressForm.Bar1.Value = (i / .Content.End) * 100 'プログレスバーの数値変更
        Loop
    End With
    Unload ProgressForm 'プログレスバーを非表示
    Set rng = Nothing 'オブジェクトの解放
End Sub

'漢数字（二三五四一）を数値（23541）に変換する関数
Function ReplKan2Num(text As String) As Double
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim arabNums As Variant: arabNums = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
    Dim i As Long
    For i = 0 To UBound(chinNums)
        text = Replace(text, chinNums(i), arabNums(i))
    Next i
    ReplKan2Num = Val(StrConv(text, vbNarrow)) 'vbNarrowは入力文字列が"２３５４１"という全角数字の場合に対応させるため
End Function

'数値（23541）を漢数字（二三五四一）に単純変換する関数
Function ReplNum2Kan(num As Double) As String
    ReplNum2Kan = num
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim arabNums As Variant: arabNums = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
    Dim i As Long
    For i = 0 To UBound(chinNums)
        ReplNum2Kan = Replace(ReplNum2Kan, arabNums(i), chinNums(i))
    Next i
End Function

'15桁までの漢数字を数値変換する関数
Function ConvKan2Num(text As String, Optional digit As Long = 4) As Double
    Dim i As Long, pos As Long, posStart As Long: posStart = 1
    Dim partialValue As Double
    Dim largeNums As Variant: largeNums = IIf(digit = 4, Array("", "万", "億", "兆"), Array("", "十", "百", "千")) '大数の指定
    For i = UBound(largeNums) To 0 Step -1
        If i = 0 Then
            pos = IIf(posStart = Len(text) + 1, 0, Len(text) + 1)
        Else
            pos = InStr(text, largeNums(i))
        End If
        If pos <> 0 Then '目的の大数が無い場合は加算しない
            If pos = posStart Then '目的の大数が数字を持たない場合（ex. "二千百四十"における百の位）
                partialValue = 1
            Else
                If digit = 4 Then
                    partialValue = ConvKan2Num(Mid(text, posStart, pos - posStart), 1) '再帰処理
                Else
                    partialValue = ReplKan2Num(Mid(text, posStart, pos - posStart))
                End If
            End If
            ConvKan2Num = ConvKan2Num + partialValue * 10 ^ (digit * (i))
            posStart = pos + 1
        End If
    Next i
End Function

'4桁までの数値（2056）を漢数字（二千五十六）に変換
Function ConvNum2Kan4(ByVal num As Long) As String
    Dim i As Long
    Dim largeNums As Variant: largeNums = Array("", "十", "百", "千")
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim quo As Long 'quotient（商）
    If num < 0 Then num = -num 'エラー回避（マイナス数字はプラスにしておく）
    num = num Mod 10000 'エラー回避（5桁以上の場合は下4桁のみ対象とする）
    For i = UBound(largeNums) To 0 Step -1
        quo = num \ 10 ^ i
        num = num Mod 10 ^ i
        If quo = 0 Then
            ConvNum2Kan4 = ConvNum2Kan4 & ""
        ElseIf i <> 0 And quo = 1 Then
            ConvNum2Kan4 = ConvNum2Kan4 & largeNums(i)
        Else
            ConvNum2Kan4 = ConvNum2Kan4 & chinNums(quo) & largeNums(i)
        End If
    Next i
    If ConvNum2Kan4 = "" Then ConvNum2Kan4 = "〇"
End Function

'15桁までの数値を漢数字などに変換
Function ConvNum2Kan(num As Double, Optional typ As Long = 1) As String
    Dim numStr As String: numStr = num
    Dim largeNums As Variant: largeNums = Array("", "万", "億", "兆")
    Dim i As Long, tmpNum As Long
    ConvNum2Kan = "" '初期値（無くとも良いが明示する）
    For i = 0 To UBound(largeNums)
        tmpNum = Val(Right(numStr, 4))
        If tmpNum > 0 Then
            Select Case typ
                Case 2 '四五万八九〇〇
                    ConvNum2Kan = ReplNum2Kan(CDbl(tmpNum)) & largeNums(i) & ConvNum2Kan
                Case 3 '45万8900
                    ConvNum2Kan = tmpNum & largeNums(i) & ConvNum2Kan
                Case Else '四十五万八千九百
                    ConvNum2Kan = ConvNum2Kan4(tmpNum) & largeNums(i) & ConvNum2Kan
            End Select
        End If
        If Len(numStr) > 4 Then
            numStr = Left(numStr, Len(numStr) - 4)
        Else
            Exit For
        End If
    Next i
    If ConvNum2Kan = "" Then ConvNum2Kan = "〇"
End Function
```
以上が全てのコードとなります。

## 4-2. マーキング処理
それでは、マーキング処理から見ていきます。
マーキング処理を行ってるのは、次の４つのプロシージャとなります。

|プロシージャ名|処理の内容|他のプロシージャとの関係|
|---|---|---|
|HighlightNum|数字部分のマーキング処理|ClearHighlightOnFieldを使用|
|ClearHighlightOnField|計算フィールドのマーキング解除|HighlightNumの中で使用される|
|CrearHighlight|文書中の全てのマーキング解除||
|CrearHighlightOnSelection|選択部分のマーキング解除||

※「他のプロシージャとの関係」の項は、つまり、HighlightNumプロシージャはその処理の中で、ClearHighlightOnFieldプロシージャを呼び出すということを意味しています。

### 4-2-1. 数字部分のマーキング処理（`HighlightNum`プロシージャ）
#### 4-2-1-1. 数字部分のマーキング
`HighlightNum`プロシージャは、細かい設定を入れていて見にくいですが、単に数字部分をマーキングするだけであれば、次のようにシンプルに記述することができます。

```vb
Const numChr = "〇一二三四五六七八九十百千万億兆0123456789０１２３４５６７８９" '漢数字のみの判定であれば後半の算用数字は不要

Sub HighlightTest()
    Dim i As Long: i = 0 '指定しなくとも初期値は0となる
    Do While i < ActiveDocument.Content.End
        If InStr(numChr, ActiveDocument.Range(i, i + 1).Text) > 0 Then
            ActiveDocument.Range(i, i + 1).HighlightColorIndex = wdYellow
        End If
        i = i + 1
    Loop
End Sub
```
冒頭の定数`Const numChr`は、どの文字を数字として拾うかについて定義しています。
文書の先頭から１文字ずつループさせて（`Do While i < ActiveDocument.Content.End`のところ）、`InStr関数`で数字か否かを判定して数字であればマーキングをしています。
詳細は「[WORD文書の範囲を指定して操作する ](https://qiita.com/t-yama-3/items/89300fbab045738b604e#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%891-2-1%E6%96%87%E6%9B%B8%E4%B8%AD%E3%81%AE%E6%95%B0%E5%AD%97%E9%83%A8%E5%88%86%E3%82%92%E9%BB%84%E8%89%B2%E3%81%A7%E3%83%9E%E3%83%BC%E3%82%AD%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B%E4%BE%8B)」という記事に書いていますので、そちらをご参照ください。

#### 4-2-1-2. 確認メッセージ
`HighlightNum`プロシージャの冒頭の３行は、確認メッセージです。

```vb
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("文書中の数字部分を一括してマーキングします" & vbCrLf & "このまま処理を続行しますか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
```
メッセージボックスを表示して処理を続行するかを確認しているだけです。
これは無くともプログラムは正常に実行されるので、省略しても構いません。

#### 4-2-1-3. プログレスバーの表示
`HighlightNum`プロシージャのうち、プログレスバーを制御している部分を抜き出すと、おおよそ次のようになります（若干加工しています）。

```vb
    ProgressForm.Show vbModeless'プログレスバーを表示
    Dim i As Long: i = 0
    Do While i < ActiveDocument.Content.End
        i = i + 1
        ProgressForm.Bar1.Value = (i / ActiveDocument.Content.End) * 100 'プログレスバーの数値変更
    Loop
    Unload ProgressForm 'プログレスバーを非表示
```

標準モジュールからフォーム（クラスモジュール）の操作をする場合は、最初にフォーム名（クラス名）を記述してから、その後に続けて、使用したいメソッド、プロパティ、オブジェクトを記述します。

具体的にみると、１行目は、`ProgressForm`というクラス（フォーム）について、`Showメソッド`を用いてフォームを表示するという処理を行っています。これにより、プログレスバーが表示されます。
また、最後の行は、[Unloadステートメント](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/unload-statement)を使用して、フォームを閉じる処理をしています（処理上はフォームが削除されています）。

5行目の`ProgressForm.Bar1.Value`は、`ProgressForm`クラスの`Bar1`オブジェクト（つまりプログレスバーの部分）を呼び出して、`.Value`でその値を表しています。
これに、`[現在の文字位置]/[全体の文字数]*100`、つまり「処理進捗のパーセント」を代入しているということになります。

なお、デフォルトでは、プログレスバーの最小値は`0`、最大値は`100`となっていますが、この値を変更することも可能です。
色々なサイトで解説されていますので、興味があれば調べてみてください。

### 4-2-2. 計算フィールドのマーキング解除（`ClearHighlightOnField`プロシージャ）
単純に数字かどうかを判定してマーキングを実行すると、WORD文章に「ふりがな」がある場合に、その文字を数字と読み取ってしまいます。
例えば、次のような文書の場合、ふりがなが付いている「懲役」のところは**`計算フィールド`**というものになっています。
![2020-10-04 234137.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/db380d15-af7f-32c1-3925-189642ecb618.png)
上記文書の「懲役」の文字を選択して右クリックをすると「フィールドコードの表示／非表示」というメニューが出ますのでそれを選択すると、次のように表示されます。
![2020-10-04 234245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/8a28665d-13d3-2182-6057-aaeaf314760e.png)
つまり、ルビをふるために、`EQ \* jc2 \* "Font:ＭＳ ゴシック" \* hps10 \o\ad(\s\up 9(ちょうえき),懲役)`というコードが埋め込まれており、そのコードの中に数字を持ってしまっているため、数字であると判定されてしまうことになります。
このマーキングを解除するために、次の`ClearHighlightOnField`プロシージャを用意してます。

```vb
'計算フィールドのマーキング解除
Sub ClearHighlightOnField()
    Dim fld As Field
    Dim rng As Range: Set rng = Selection.Range '選択範囲（Range）の初期状態を記録
    For Each fld In ActiveDocument.Fields
        fld.Select 'Rangeプロパティを持たないため範囲選択（Select）を行う
        Selection.Range.HighlightColorIndex = wdNoHighlight 'SelectionオブジェクトのRengeプロパティから領域を取得する
    Next
    rng.Select: Set rng = Nothing '選択範囲（Range）を初期状態に戻す
End Sub
```

コードの細かい説明はしませんが、`ActiveDocument.Fields`の一文で文章中の全ての計算フィールドを取得して、[For Eachステートメント](https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/using-for-eachnext-statements)により、それらのハイライト全てを解除する処理をしています。
このプロシージャを、`HighlightNum`プロシージャの最後の方で呼び出して、ふりがな部分（計算フィールド部分）のマーキングを全て解除しているということになります。

### 4-2-3. 文章中全てのマーキング解除（`CrearHighlight`プロシージャ）
文章中のマーキングを全て解除するプロシージャです。

```vb
'全マーキング解除
Sub CrearHighlight()
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("文書中の全てのマーキングをクリアしてよいですか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
    
    ActiveDocument.Content.HighlightColorIndex = wdNoHighlight '文書全体のマーキングをクリア
End Sub
```

最初の3行は確認メッセージですので、実際に解除を行っているのは最後の１行のみとなります。


`ActiveDocument.Content.HighlightColorIndex = wdNoHighlight`

この意味は、現在アクティブな文書（ActiveDocumentオブジェクト）の全文（Contentプロパティ）のマーキング処理（HighlightColorIndexプロパティ）を無し（wdNoHighlight）とする、ということになります。

### 4-2-4. 選択部分のマーキング解除（`CrearHighlightOnSelection`プロシージャ）
カーソルで選択している範囲のみ、マーキングを解除するプロシージャです。

```vb
'選択部分マーキング解除
Sub CrearHighlightOnSelection()
    Selection.Range.HighlightColorIndex = wdNoHighlight
End Sub
```

コードの意味は、現在の選択範囲（Selectionオブジェクト）の領域（Rangeプロパティ）のマーキング処理（HighlightColorIndexプロパティ）を無し（wdNoHighlight）とする、ということになります。

## 4-3. 数字変換処理
次に、数字変換処理を見ていきます。
数字変換処理を行ってるのは、次の6つのプロシージャとなります。

|プロシージャ名|処理の内容|他のプロシージャとの関係|
|---|---|---|
|ConvNum|マーキングされた数字の変換処理|以下の5つの関数（ReplKan2Num～ConvNum2Kan）全てを使用|
|ReplKan2Num|漢数字（二三五四一）を数値（23541）に変換|（単独で処理可能）|
|ReplNum2Kan|数値（23541）を漢数字（二三五四一）に単純変換|（単独で処理可能）|
|ConvKan2Num|15桁までの漢数字を数値変換|ReplKan2Numを使用|
|ConvNum2Kan4|4桁までの数値（2056）を漢数字（二千五十六）に変換|（単独で処理可能）|
|ConvNum2Kan|15桁までの数値を漢数字などに変換|ReplNum2Kan、ConvNum2Kan4を使用|

### 4-3-1. マーキングされた数字の変換処理（`ConvNum`プロシージャ）
`ConvNum`プロシージャの完成形については「**4-1. 【参考】標準モジュールのソースコード（完成形）**」に記載してあるとおりです。
ここでは、プロシージャの中から個別に機能を抜粋して、コードの内容をみていきます。

#### 4-3-1-1. 数字の変換処理
`ConvNum`プロシージャのうち、数字に変換する部分のみを抜粋して記述すると次のようになります。
複雑にならないように、漢数字のみに変換するコードにしています。

```vb
Sub ConvNumTest()
    Dim i As Long
    Dim s As Long '数字部分のスタート位置を記録する変数
    Dim rng As Range
    Dim numFlg As Boolean: numFlg = False '数字の場合にTrueとするフラグ

    Do While i < ActiveDocument.Content.End
        If InStr(numChr, ActiveDocument.Range(i, i + 1).text) > 0 Then '文字が数字であるか否かの判定
            If numFlg = False Then
                s = i '数字が出現したスタート位置を記録
                numFlg = True '数字部分に入ったためTrueに変更
            End If
        Else
            If numFlg = True Then 'numFlgがTrueであれば直前までが数字であったということ
                Set rng = ActiveDocument.Range(s, i) '数字部分のRangeを変数rngに設定
                rng.text = ConvKan2Num(rng.text) 'ConvKan2Num関数を使って漢数字を算用数字に変換
                i = s + Len(rng.text) '変換後の数字の末尾にiを再設定（文字数が変わるため）
                numFlg = False
            End If
        End If
        i = i + 1
    Loop
End Sub
```

このプロシージャを実行するには、算用数字を漢数字に変換する`ConvKan2Num`関数及び`ReplNum2Kan`関数が必要となります。

マーキング処理をする場合は1文字ずつ処理することで足りましたが、数字を漢数字に変換する場合は、数字部分を1つの範囲（Range）として取り出して変換する必要があります。
例えば、`手数料は10500円`という文字列があった場合は、`10500`の5文字を取り出して`一万五百`というように変換することになります。
ここでは、数字部分の開始位置を変数`s`に入れて、終了位置を変数`i`として、Rangeメソッドを使用してこの範囲の数字部分の領域を取得した上で、算用数字への変換処理を行っています。

このコードを基本として、必要な処理を追加していきます。
追加するのは「マーキング部分のみを変換すること」及び「変換候補として算用数字、漢数字の両方を指定できること」の2つです。
これを実現するためには、上記コードの13行目から18行目まで（`If numFlg = True Then`から`End If`まで）の部分を次のように変更することになります。

```vb
    If numFlg = True Then 'numFlgがTrueであれば直前までが数字であったということ
        Set rng = .Range(s, i) '数字部分のRangeを変数rngに設定
        If rng.HighlightColorIndex <> wdNoHighlight Then
            If typ = 0 Then
                rng.text = Format(ConvKan2Num(Replace(rng.text, ",", "")), "###,###") 'ConvKan2Num関数を使って漢数字を算用数字に変換
            Else
                rng.text = ConvNum2Kan(ConvKan2Num(Replace(rng.text, ",", "")), typ) 'ConvNum2Kan関数を使って算用数字を漢数字に変換
            End If
            If .TrackRevisions Then '変更履歴機能がオンかオフか
                i = i + Len(rng.text) '変換後の数字の末尾にiを再設定（文字数が変わるため）
            Else
                i = s + Len(rng.text) '変換後の数字の末尾にiを再設定（文字数が変わるため）
            End If
        End If
        numFlg = False
    End If
```

マーキング部分のみ変換するように制御しているのは、3行目にある次のIf文です。
`If rng.HighlightColorIndex <> wdNoHighlight Then`

変換候補を漢数字と算用数字で選択できるようにしているのは、4行目から8行目まで（`If typ = 0 Then`から`End If`まで）のところです。

なお、「変更履歴機能」をオンにしていると、削除された文字もデータ上に残ってしまうため、変数`i`の進め方を変える必要があります。
これを制御しているのが、9行目から13行目まで（`If .TrackRevisions Then`から`End If`まで）のところです。
変更履歴のオンオフは、このIf文の条件となっている[Document.TrackRevisionsプロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.office.tools.word.document.trackrevisions?view=vsto-2017)で取得・操作をすることが可能です。



#### 4-3-1-2. 確認メッセージ
`ConvNum`プロシージャの冒頭の３行は、ただの確認メッセージです。

```vb
    '確認メッセージを表示
    Dim ans As Long
    ans = MsgBox("マーキングされている数字の変換を実行します" & vbCrLf & "このまま処理を続行しますか？", vbYesNo + vbQuestion, "確認メッセージ")
    If ans = vbNo Then Exit Sub
```
これが無くともプログラムは正常に実行されるので、省略しても構いません。

#### 4-3-1-3. プログレスバーの表示
`ConvNum`プロシージャのうち、プログレスバーを制御している部分を抜き出すと、おおよそ次のようになります。

```vb
    ProgressForm.Show vbModeless'プログレスバーを表示
    Dim i As Long: i = 0
    Do While i < ActiveDocument.Content.End
        i = i + 1
        ProgressForm.Bar1.Value = (i / ActiveDocument.Content.End) * 100 'プログレスバーの数値変更
    Loop
    Unload ProgressForm 'プログレスバーを非表示
```

この内容は、先に「4-2-1-3」で説明したとおりです。

### 4-3-2. 漢数字（二三五四一）を数値（23541）に変換（`ReplKan2Num`プロシージャ）
これは単純に[Replace関数](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/replace-function)を使って、`一～九`を`1～9`に変換しているだけです。
もっとシンプルで適切な書き方があるかもしれませんが、私の知識で書くとこのようになります。

```vb
Function ReplKan2Num(text As String) As Double
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim arabNums As Variant: arabNums = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
    Dim i As Long
    For i = 0 To UBound(chinNums)
        text = Replace(text, chinNums(i), arabNums(i))
    Next i
    ReplKan2Num = Val(StrConv(text, vbNarrow)) 'vbNarrowは入力文字列が"２３５４１"という全角数字の場合に対応させるため
End Function
```
### 4-3-3. 数値（23541）を漢数字（二三五四一）に単純変換（`ReplNum2Kan`プロシージャ）
これも上記と同様に、単純に[Replace関数](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/replace-function)を使って、`1～9`を`一～九`に変換しているだけです。

```vb
Function ReplNum2Kan(num As Double) As String
    ReplNum2Kan = num
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim arabNums As Variant: arabNums = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
    Dim i As Long
    For i = 0 To UBound(chinNums)
        ReplNum2Kan = Replace(ReplNum2Kan, arabNums(i), chinNums(i))
    Next i
End Function
```
### 4-3-4. 15桁までの漢数字を数値変換（`ConvKan2Num`プロシージャ）
漢数字を数字変換するコードは、WEB上で様々に掲載されていると思います。
どういうアルゴリズムを使うかで、書き方は人によりけりです。
下記のコードで使用しているアルゴリズムは、過去の記事「[JavaScriptで文字列中の漢数字を算用数字に変換する](https://qiita.com/t-yama-3/items/9819600cec53723472d3#1-%E5%A4%89%E6%8F%9B%E3%81%AE%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)」において説明していますので、気になる方はご参照ください。

```vb
Function ConvKan2Num(text As String, Optional digit As Long = 4) As Double
    Dim i As Long, pos As Long, posStart As Long: posStart = 1
    Dim partialValue As Double
    Dim largeNums As Variant: largeNums = IIf(digit = 4, Array("", "万", "億", "兆"), Array("", "十", "百", "千")) '大数の指定
    For i = UBound(largeNums) To 0 Step -1
        If i = 0 Then
            pos = IIf(posStart = Len(text) + 1, 0, Len(text) + 1)
        Else
            pos = InStr(text, largeNums(i))
        End If
        If pos <> 0 Then '目的の大数が無い場合は加算しない
            If pos = posStart Then '目的の大数が数字を持たない場合（ex. "二千百四十"における百の位）
                partialValue = 1
            Else
                If digit = 4 Then
                    partialValue = ConvKan2Num(Mid(text, posStart, pos - posStart), 1) '再帰処理
                Else
                    partialValue = ReplKan2Num(Mid(text, posStart, pos - posStart))
                End If
            End If
            ConvKan2Num = ConvKan2Num + partialValue * 10 ^ (digit * (i))
            posStart = pos + 1
        End If
    Next i
End Function
```
### 4-3-5. 4桁までの数値（2056）を漢数字（二千五十六）に変換（`ConvNum2Kan4`プロシージャ）
以下は4桁までの数字を漢数字に変換するコードです。

```vb
Function ConvNum2Kan4(ByVal num As Long) As String
    Dim i As Long
    Dim largeNums As Variant: largeNums = Array("", "十", "百", "千")
    Dim chinNums As Variant: chinNums = Array("〇", "一", "二", "三", "四", "五", "六", "七", "八", "九")
    Dim quo As Long 'quotient（商）
    If num < 0 Then num = -num 'エラー回避（マイナス数字はプラスにしておく）
    num = num Mod 10000 'エラー回避（5桁以上の場合は下4桁のみ対象とする）
    For i = UBound(largeNums) To 0 Step -1
        quo = num \ 10 ^ i
        num = num Mod 10 ^ i
        If quo = 0 Then
            ConvNum2Kan4 = ConvNum2Kan4 & ""
        ElseIf i <> 0 And quo = 1 Then
            ConvNum2Kan4 = ConvNum2Kan4 & largeNums(i)
        Else
            ConvNum2Kan4 = ConvNum2Kan4 & chinNums(quo) & largeNums(i)
        End If
    Next i
    If ConvNum2Kan4 = "" Then ConvNum2Kan4 = "〇"
End Function
```
それぞれの位の数字を取得する方法は、古典的なアルゴリズムを使用しています。
例えば、`5346`という数字を`1000`で割ると、商が`5`で余りが`346`となります。
そうすると、千の位が`5`ということが分かります。続いて余りの`346`を`100`で割れば、百の位が`3`ということが分かります。
このようにして情報を取得した上で、漢数字表記に置き換える処理をしています。

本当はこのアルゴリズムで、15桁分の数字全てを処理してしまいたいところですが、VBAで整数のデータ型は`Long`が最大であり、その範囲は「-2,147,483,648～2,147,483,647」となっています。
なので、この方法では9桁の変換までしかできないことになります。

### 4-3-6. 15桁までの数値を漢数字などに変換（`ConvNum2Kan`プロシージャ）
これは15桁の数字を漢数字などに変換するコードです。

```vb
'15桁までの数値を漢数字などに変換
Function ConvNum2Kan(num As Double, Optional typ As Long = 1) As String
    Dim numStr As String: numStr = num
    Dim largeNums As Variant: largeNums = Array("", "万", "億", "兆")
    Dim i As Long, tmpNum As Long
    ConvNum2Kan = "" '初期値（無くとも良いが明示する）
    For i = 0 To UBound(largeNums)
        tmpNum = Val(Right(numStr, 4))
        If tmpNum > 0 Then
            Select Case typ
                Case 2 '四五万八九〇〇
                    ConvNum2Kan = ReplNum2Kan(CDbl(tmpNum)) & largeNums(i) & ConvNum2Kan
                Case 3 '45万8900
                    ConvNum2Kan = tmpNum & largeNums(i) & ConvNum2Kan
                Case Else '四十五万八千九百
                    ConvNum2Kan = ConvNum2Kan4(tmpNum) & largeNums(i) & ConvNum2Kan
            End Select
        End If
        If Len(numStr) > 4 Then
            numStr = Left(numStr, Len(numStr) - 4)
        Else
            Exit For
        End If
    Next i
    If ConvNum2Kan = "" Then ConvNum2Kan = "〇"
End Function
```
VBAでは15桁の**整数**を格納できるデータ型がないので（たぶん）、一旦`Double`型から`String`型に変換して、4桁ずつ切り取って処理をしています。

なお、`45万8900`というような数字と漢数字が混合した表記にもできるように、引数`typ`の数値に応じて表記が変更されるようにしています（コード中のコメント文を参照してください）。
なお、この`typ`に当てられる数字は、「**2-2-3. コンボボックスのソースコード**」で作成したリストのインデックスと対応するように調整しています。
具体的には、次のような区分となっています。

|Index|リスト項目|表記例|
|---|---|---|
|0|算用数字|538,000,000|
|1|漢数字1（十百千を含む）|五億三千八百万|
|2|漢数字2（十百千を含まない）|五億三八〇〇万|
|3|数字・漢字混合|5億3800万|

標準モジュールの内容は、以上のとおりです。
記載するコードの完成形は「**4-1. 【参考】標準モジュールのソースコード（完成形）**」のようになります。

# 5. フォームと標準モジュールの関連付け
さて、最後に、標準モジュールで作成したプログラムをフォームボタンで操作できるようにします。

まず、実行内容を確認するために、何でも良いのでWORD文書に文字列を入れておきます。
私は、漢数字が適度に使用されている「消費税法64条」の条文をコピペしています（[e-Gov 消費税法](https://elaws.e-gov.go.jp/search/elawsSearch/elaws_search/lsg0500/detail?lawId=363AC0000000108)）。
加えて、ふりがなが入っていた場合の挙動を確認するために、「懲役」のところにルビを入れています。
![2020-10-05 235713.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2e433edf-26eb-8449-d483-25aca5c5b95d.png)
それでは、「**2-2. フォームのソースコード作成**」が終わった時点のコードに処理を追加していきます。
![2020-10-05 232756.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/69316d20-d029-e85c-a9b5-6011e6597ea8.png)
上図の赤枠のところを、次のコードに書き直します。

```vb
Private Sub HighlightNumBtn_Click()
    Call HighlightNum
End Sub
```
`Call HighlightNum`の一文で、標準モジュール（`ConvNumModule`）の`HighlightNum`プロシージャを呼び出して実行しています。

フォームを開いて「数字部分の自動マーキング」ボタンをクリックして、次のようになっていれば成功です。
![2020-10-05 235925.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/12137c69-5471-1678-598f-6b8466be0f08.png)

それでは、他のボタンも関連付けを行っていきます。
メインフォームのボタンと標準モジュールのプロシージャの関係付けを一覧にすると次のとおりです。

|ボタン|オブジェクト名|関連付けるプロシージャ|備考|
|---|---|---|---|
|数字部分の自動マーキング|HighlightNumBtn|HighlightNum|※これは既に作成済み|
|マーキング全てをクリア|CrearHighlightBtn|CrearHighlight||
|選択部分のマーキングをクリア|CrearHighlightOnSelectionBtn|CrearHighlightOnSelection||
|マーキング部分の数字変換を実行|ConvKan2NumBtn|ConvNum|引数としてコンボボックスのインデックス番号を渡す|

こう見ると、最後のオブジェクト名は「ConvKan2NumBtn」ではなく「ConvNumBtn」とすべきでしたね（ここはこのままにしておきます）。

表のとおりに、次のような3つのプロシージャ（clickイベント）を追加します。

```vb
Private Sub CrearHighlightBtn_Click()
    Call CrearHighlight
End Sub

Private Sub CrearHighlightOnSelectionBtn_Click()
    Call CrearHighlightOnSelection
End Sub

Private Sub ConvKan2NumBtn_Click()
    Call ConvNum(SelectCmb.ListIndex)
End Sub
```
VBAはプロシージャの順番が変わっても処理に影響しないので、コードを見る人が分かりやすい順番で並べておきます。
これで、一応ツールなるものが完成しました。

# 6. ツールの配布方法
ツールは完成しましたが、次のような問題が残ります。

```
・毎回、マクロから「OpenForm」を使ってフォームを開かないとならないのか？
・全てのWORD文書でこのツールを使うにはどうしたら良いか？
・他の人に使ってもらうにはどう配布したら良いか？
```
ここではアドインによる方法について書いておきます。
色々なサイトで解説されている手法なので、ここに書くまでもないのですが、以下、ごく簡単に基本部分だけ紹介しておきます。

参考サイト：[Wordアドインの使い方](https://daikocrea.co.jp/2018/11/06/word%E3%82%A2%E3%83%89%E3%82%A4%E3%83%B3%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/) など

## 6-1. ツールバーにフォームを登録する
WORDには「クイックアクセスツールバー」なるものがあります。
![2020-10-06 002912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/4b8ae8d2-e4f8-d2e4-f113-4426b6ae76fe.png)
よく使う処理を、赤枠のところにアイコンで並べて使うものです。
ここに、フォームを開くボタンを設置します。

WORD文書のメニューの「ファイル」から「オプション」を開き「クイックアクセスツールバー」を選択します。
![2020-10-06 003914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/12a4311b-ea35-17a9-b72d-68abc3f3f058.png)
そして、「コマンドの選択」のドロップダウンメニューから「マクロ」を選択し、「クイックアクセスツールバーのユーザー設定」から「[ファイル名]に適用」を選択します。
私は、ファイル名を「SampleTool.docm」としているので、画面のように表示されています。
![2020-10-06 004049.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/469bc2b3-e1a6-a673-a366-d612009de686.png)
今回ツールバーに登録したいのは「OpenForm」というマクロなので、下図のように選択して「追加」ボタンを押します。
すると、右側の欄に「OpenForm」のマクロが追加されますので、OKボタンを押して終了します。
![2020-10-06 004522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/398b933d-6539-8376-900e-98b95999172b.png)
次のように、マクロのアイコンが登録されていると思います。
今後は、このボタンを押すことで、いつでもフォームが開けます。
![2020-10-06 005015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/9d2401d8-ce4e-7a88-ac95-a6e395360a00.png)

## 6-2. 全てのWORD文書でマクロを有効にする
全ての文書でマクロを使えるようにするには、まず、拡張子を`.dotm`にした「マクロ有効テンプレート」を作成します。
作成したWORDファイルを「名前を付けて保存」から、マクロ有効テンプレートとして保存します。

なお、ファイルの保存先は、デスクトップなど自分が分かりやすい場所に保存してください（私の手元では、自動的に`C:\Users\username\Documents\Office のカスタム テンプレート`というフォルダが保存先に選択されていまいます。）。
![2020-10-06 005904.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/c633bc5b-6d3b-7364-b35e-00b8e832fbb3.png)
次に、テンプレートを置く場所の確認です。
WORD文書のメニューの「ファイル」から「オプション」を開き「詳細設定」を選択します。
この下の方にある「全般」の項目に、「ファイルの場所」というボタンがあるので、これをクリックします。
![2020-10-06 005513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2a649b2a-b63c-b8e3-1da6-39a4901eaded.png)
次のような画面が表示されますので、「スタートアップ」のところをダブルクリックで開きます。
![2020-10-06 011445.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/526620ed-8c0f-7700-5a72-d3c621c76210.png)
すると、次のようにSTARTUPフォルダの場所が確認できます。
![2020-10-06 011855.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/45f90d94-0185-f910-2779-d801a352634b.png)
フォルダの場所は決して変更しないようにして、この赤枠部分のディレクトリだけをコピーして、別途フォルダを開きます。
このSTARTUPフォルダに先ほど作った「マクロ有効テンプレート」（拡張子`.dotm`）を保存して終わりです。
![2020-10-06 012445.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/6c54b3ad-48ff-030f-8a20-1f656586002f.png)
以上の作業により、どのWORD文書を開いても、「クイックアクセスツールバー」からフォームを開いてツールを使用することができるようになります。

## 6-3. 他の人に使ってもらう方法
他の人に使ってもらうには、「**6-2. 全てのWORD文書でマクロを有効にする**」で作成した「マクロ有効テンプレート」（拡張子`.dotm`）を配布して、そのマクロ有効テンプレートをその方の「STARTUPフォルダ」に保存してもらうことでツールを使用できるようになります。

# 7. おわりに
これからVBAを始める方に、何らかのお役に立てば幸いです。