はじめに
これは、Visual Basic Advent Calendar 2019の9日目の記事となります。
Format について
VBScriptを使用していて不満点が多くあるけど、その中でもFormat関数が貧弱なところがとても不便です。
下記のようにFormatXXXXXと機能ごとに分割されてしまっている。
FormatDateTime関数
FormatCurrency 関数
FormatNumber 関数
FormatPercent 関数
FormatDateTime関数は日時を書式文字列化して返却する関数ですが、時刻が0埋めにならないなど使いにくい。
自分でも下記記事を書いてみたりしました。
.NETのFormat関数を呼び出して使えるのが一番いいのですが、使えないと思い込んでいて PowerShell を呼び出してみるなど試していました。最近ネットで見つけたのが下記サイトになります。
CreateObjectで.NETのStringクラスを作ればString.Formatを使える……、と思ったけどStringクラスは利用できず。
だけどStringBuilderクラスは利用できた。StringBuilderのAppendFormatメソッドならFormat関数の代わりになる。
VBScriptでのFormat関数の代わり (書式文字列を使いたい)
' StringBuilderクラスのインスタンスを生成
dim sb1: set sb1 = CreateObject("System.Text.StringBuilder")
' 配列で指定した値(1, "now", now) を
' それぞれ<デフォルト>, <幅8文字分>, <幅12文字分, yyyy/MM/dd>の書式で
' StringBuilderに追加
sb1.AppendFormat_4 "{0}, {1,8}:{2,12:yyyy/MM/dd}",Array(1, "now", now)
' StringBuilderを文字列に変換
wscript.echo sb1.toString
AppendFormatの使い方や書式指定子の書き方はSprintfに似ている。
これを使えば、日付時刻書式、文字数と右寄せ・左寄せや3桁区切り、小数の表示桁数、ゼロパディングが使える。
※和暦には対応できていないようです。
「CreateObject("System.Text.StringBuilder")」で検索してみたら、いろいろ見つけた。
仕組み
.NETのクラスの一部はCOM相互運用機能が実装されている。どれかはレジストリの「HKEY_CLASSES_ROOT」を参照する。
WSHではメソッドのoverloadなんて概念は存在しないでの、引数の数が違うだけの同名のメソッドは普通に叩くとエラーとなる。その場合はxxx_2のように最後にアンダースコア+数字をくっつけて区別する
- Microsoft TechNet 2007年1月号 HEY, SCRIPTING GUY!
- スクリプトから使えるよう、.NETのオーバーロードのサフィックスを調べる。
- スクリプトから.NETのSystem.Text.StringBuilderを使う。
- 連想配列にCollectionを使わない理由
- .NET Frameworkの素敵機能をJScriptで使いたい
注意点
Windows 8、Windows 8.1、Windows Server 2012以降では、.NET 3.5 が最初からインストールされていません。
.NET 4.5 からは、.NET型をCOMインターフェイスとして公開することを停止したため、"System.Text.StringBuilder" や "System.Collections.ArrayList" などがエラーになるようになりました。
このため、Windows 10 ユーザーに配布するには注意が必要です。
対応としては、.NET 3.5をインストールすることで使えるようになります。
それ以外では、「cscript.exe.activation_config」という名前のアクティベーション設定ファイルを作成することで使用できるようです。
- Usage of .NET Collections types in VBScript is not supported after .NET 4.5
- Windows10にしたらVBAから.Net Frameworkが使えなくなった
- Windows10で実行したスクリプトでArrayListの作成がエラーになった
- How can I run PowerShell with the .NET 4 runtime?
最後に
VBScript内だけであれば簡単なFormatは自作してしまえばいいですが、バッチファイルで日時計算(9時間前計算)とか一時的にVBSを使用したい場合、この方法は便利です。
echo dim sb1:set sb1=CreateObject("System.Text.StringBuilder"):sb1.AppendFormat_4 "{0:yyyy-MM-ddTHH:mm:ss}",Array(DateAdd("h",-9,Replace("%1","T"," "))):WScript.Echo sb1.toString > tmp.vbs
for /f "tokens=1" %%A in ('cscript //nologo tmp.vbs') do set RETVAL=%%A
del tmp.vbs