VBScriptをお手軽にデバッグして開発する方法

# 概要
　VBScriptは「コンパイラが要らない」「実行環境はWindowsがあればいい」、その上「Windowsの動作なら大抵のことが出来る」とちょっとしたプログラムを書くのなら今なお使える言語ですがデバッグが大変です。
　そこでOfficeについてくる Visual Basic Editor(VBE)を工夫して使うことで、お手軽にデバッグする方法をご紹介します。

# VBScriptは使える子だけど、デバッグが難しい
　VBScript(以下VBS)のプログラムは簡単に作れます。メモ帳やサクラエディタなどのエディタで、例えば、`msgbox "test"` と入力し、拡張子を".vbs"で保存すれば動くのです。凄い手軽。簡単すぎ！
　筆者は非プログラマーの方に「プログラミングってこうやるんです」と説明する時に使ったりします。「ね？簡単でしょ？」って。
![msgbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/fb803814-2ca0-c9d8-4a38-25b8819f2b65.png)

　しかしながら「書く」のと「実行する」のは簡単でもデバッグするのが難しいです。やはり開発をするにはデバッガーがないと大変です。万能ソースコードエディタである Visual Studio Codeに VBScript用のデバッガーがあればいいのになと思いますが、今のところ無いようです。「無いのなら、自分で作ろうプログラム」が信条ですが生憎と作り方を知りません。どうやって作るんだろ？

# VBE(Visual Basic Editor)を使う
　そこでVisual Basic Editor(以下VBE)が代用できないかと考えました。
　ExcelやWordといったOfficeには、Visual Basic For Application(以下VBA)用のエディタVBEが用意されています。VBSとVBAは親戚みたいなものですから、これを使うのがいいでしょう。

## VBAとVBSの差を吸収する
　VBAとVBSは親戚のようなものと言ってもそれなりに違いがあります。

1. VBSでは変数の型指定ができない。
2. VBSでは実行するためのメインコードが必要ないが、VBAには必要になる。
3. VBSでは使えず、VBAで使える機能がある
    1. [VBA の機能で VBScript に含まれていない機能](https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392401(v=msdn.10))
4. VBAでは使えず、VBSでは使える機能がある。
    1. VBSでは`WScript` が使える
    2. [VBScript の機能で VBA に含まれていない機能](https://docs.microsoft.com/ja-jp/previous-versions/windows/scripting/cc392354(v=msdn.10))

　これらを次のやり方で解決します。（一部解決できていません）

1. VBAでも型指定せずに宣言する。例： `Dim a As String` ではなく、`Dim a` と記述する。
2. VBAには`Sub Main()`を作り、VBSではトップで `Main()` を呼び出すようにする。
3. VBAでしか使えない機能は使わないよう気を付ける[^1]。
4. VBSの機能をVBAでも使えるようにする。
    1. VBAで`WScript`に相当する機能をエミュレートする。
    2. RegExpは`CreateObject("VBScript.RegExp") `で呼び出す。
    3. `Eval()`と`Execute()`については残念ながらエミュレート方法は分かりませんでした[^2]。別のモジュールに`Eval()`と`Execute()`の名前だけのプロシージャを作っておけばコンパイルは通るのでデバッグ自体は別の方法で行う必要があります。

[^1]: もし使ってしまったとしてもVBSとして実行する時にエラーが発生するので、適宜確認しながら作っていければ気づけるはずです。これは`Dim a As String`と書いてしまった時も有効です。

[^2]: `Eval()`はAccessに似たような機能があるので参照設定で呼び出して使用できないかと考えましたが、文字中に変数があると出来ないです。`Execute()`は動的プログラミング([VBAで動的にコード生成＆実行](http://blog.clockahead.com/2014/06/vba.html))で解決できそうかと思いましたが、実行するプロシージャが事前に存在しないとVBEのコンパイルが通らないので無理っぽいです。動的プログラミングを使って、`Eval()`の中身を一度関数化する方法も考えましたが、やはり変数がネックになってどうにも……。

## WScript機能をVBAでエミュレートとする
　WScriptをエミュレートするWScriptObjを作成します。全部作る必要はなく必要になった機能を実装していくのいいでしょう。下記の例では、`Sleep()`, `ScriptFullName()`,`ScriptName()`,`Quit()`を実装しています。
　なお、このエミュレート機能をモジュールではなく、クラスで作っているのはモジュールで作ってしまうとモジュール名なしで実行できてしまうからです。

```vb:WScriptObj.cls
Option Explicit
Public Sub Sleep(ByVal time)
    Dim tempDate As Date    
    time = time / 1000    
    tempDate = DateAdd("s", time, Now)
    Do
        DoEvents        
    Loop While Now < tempDate    
End Sub

Public Function ScriptFullName()
    ScriptFullName = ThisWorkbook.FullName
End Function

Public Function ScriptName()
    ScriptName = ThisWorkbook.Name
End Function

Public Sub Quit()
    End
End Sub
```

　WScriptObjを作成したところのキャプチャ画面は次の通りです。
![VBE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/393e0885-660c-f3d2-477e-4429edafc596.png)


# VBEでのVBSの開発例
　次のコードはVBEでの開発しているVBSのコード例です。VBEでデバッグできることを確認してみてください。トップでエミュレート用のオブジェクトとして、`Dim WScript As New WScriptObj`を宣言しています。

```vb:
Dim WScript As New WScriptObj   ' VBAの場合に使用
' Main                          ' VBSの場合に使用

' メインを実行
Public Sub Main()
    Dim a
    Dim b
    Dim c
    a = 1
    b = 2
    c = a + b
    MsgBox c

     'VBS特有の機能をVBAで使用する
    Dim RetStr, regEx, Match, Matches   ' 変数を作成します。
    Set regEx = CreateObject("VBScript.RegExp")   ' 正規表現を作成します。
    regEx.Pattern = "aiu"   ' パターンを設定します。
    regEx.IgnoreCase = True   ' 大文字と小文字を区別しないように設定します。
    regEx.Global = True   ' 文字列全体を検索するように設定します。
    Set Matches = regEx.Execute("aiueo")   ' 検索を実行します。
    For Each Match In Matches   ' Matches コレクションに対して繰り返し処理を行います。
       RetStr = RetStr & "一致する文字列が見つかった位置は、"
       RetStr = RetStr & Match.FirstIndex & " です。一致した文字列は、"
       RetStr = RetStr & Match.Value & " です。" & vbCrLf
    Next
    MsgBox RetStr               '正規表現結果を出力する   
    WScript.Sleep 3000          ' 3秒待機        
    MsgBox WScript.ScriptName   ' 自身の名前を呼び出す
    WScript.Quit    ' 終了する    
    MsgBox "ここは実行されない"    
End Sub
```
　VBEでVBSを開発している画面キャプチャ
![VBEでVBS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/7c5996d4-cb7a-c6cc-2f90-6006b63d8ba9.png)


# VBSとして保存する
　作成したスクリプトを拡張子.vbsにして保存します。1行目をコメントアウトし、2行目をコメントから外します。

```vb:
'Dim WScript As New WScriptObj   ' VBAの場合に使用
 Main                          ' VBSの場合に使用
```
　これでVBEで作ったVBSが動くようになります。

# まとめ
- VBScript は使える子だけどデバッグが難しい。VBA用のエディタを使用するのが一番お手軽でしょう。
- VBA特有の機能は使用しないようにして、VBS特有の機能はVBAでエミュレートして解決します。
- ただし、`Eval()`と`Execute()`のエミュレートは残念ながら私にはできなかったので別のデバッグ方法が必要です。