←
▼
▲
グローバル変数を、1つのオブジェクトにまとめると、アプリケーションや組み合わせる
ライブラリが使えるグローバル変数名に制限が少なくなります。 言いかえれば、名前空間を
汚染することが最小限の抑えることができます。
Sub SampleFunction()
Set g = g_VBScriptLibraryX
g.DoFunction
g.Variable = 1
End Sub
関数の定義は、クラスの中のメソッドに定義します。
Dim g_VBScriptLibraryX
Set g_VBScriptLibraryX = new VBScriptLibraryX_Class
Class VBScriptLibraryX_Class
Public LibraryFunction
Public LibraryVariable
Private Sub Class_Initialize()
Set g = Me
Set g.LibraryFunction = GetRef( "LibraryFunction" )
End Sub
End Class
Sub LibraryFunction()
'// ...
End Sub
すでにある関数の定義から、名前空間の汚染に対策するまでの移行期間では、
次のように、関数の参照をメンバー変数に代入します。
(なお、VBScript では、匿名関数を定義できません。)
Dim g_VBScriptLibraryX
Set g_VBScriptLibraryX = new VBScriptLibraryX_Class
Class VBScriptLibraryX_Class
Public Sub LibraryFunction()
'// ...
End Sub
End Class
VBScript では、クラスをクラスの中に入れることができません。
オブジェクトを生成するメソッド(new_<クラス名>)を用意し、実際のクラス名の先頭に、固有
のライブラリの名前を付けるようにします。
Class VBScriptLibraryX_Class
Public new_SampleClass
Private Sub Class_Initialize()
Set g = Me
Set g.new_SampleClass = GetRef( "new_VBScriptLibraryX_SampleClass" )
End Sub
End Class
Class VBScriptLibraryX_SampleClass
'// ...
End Class
Function new_VBScriptLibraryX_SampleClass()
Set new_VBScriptLibraryX_SampleClass = new VBScriptLibraryX_SampleClass
End Function
Sub SampleFunction()
Set g = g_VBScriptLibraryX
Set object = g.new_VBScriptLibraryX_SampleClass()
End Sub
オブジェクトを生成するときは、次のようになります。
未確認
この問題の対策は、ライブラリ固有の長めの名前のグローバル変数を使い、ライブラリを
使うときは、1文字の変数に代入してから使います。 なお、すべての関数の先頭に、この
代入が必要になります。
Dim g_VBScriptLibraryX
Set g_VBScriptLibraryX = new VBScriptLibraryX_Class
Class VBScriptLibraryX_Class
Public LibraryVariable
Private Sub Class_Initialize()
LibraryVariable = 1
End Sub
End Class
変数は、メンバー変数にします。
VBScript のクラスは、動的にメンバー変数を追加することができません。
このため、ライブラリが、複数の .vbs ファイルに分かれていると、関数などを1つの
クラスのメソッドにまとめることができません。
1つのファイルに集めるスクリプトを動かしてから、ライブラリを動かす(関数定義する)
とよいでしょう。
参考
すでにあるグローバル変数の定義から、名前空間の汚染に対策するまでの移行期間では、
次のように、プロパティを使います。
Dim g_VBScriptLibraryX
Set g_VBScriptLibraryX = new VBScriptLibraryX_Class
Class VBScriptLibraryX_Class
'//[Variable]
Public Property Let Variable( x ) : g_Variable = x : End Property
Public Property Get Variable() : Variable = g_Variable : End Property
End Class
Dim g_Variable
←
▼
▲
Dim a(), b
ReDim a(1), b(1)
a(1) = "abc"
WScript.Echo "1=" & a(1) ' 1=abc
ReDim Preserve a(2)
WScript.Echo "0=" & a(0) ' 0=
WScript.Echo "1=" & a(1) ' 1=abc
WScript.Echo "2=" & a(2) ' 2=
'WScript.Echo "3=" & a(3) ' エラー
Array_echo( a )
Sub Array_echo( arr )
Dim i
WScript.Echo "UBound="&UBound( arr )
For Each i In arr
WScript.Echo "each = " + i
Next
End Sub
ReDim Preserve は、要素の内容を
保持したまま、要素の数を変える。
ReDim するなら Dim は不要。 () も不要。
ReDim a(1) で、a(0)〜a(1) が使える
For Each が使える
1=abc
0=
1=abc
2=
UBound=2
each =
each = abc
each =
出力
配列は引数に渡せる
Dim a() とすると a は配列になりますが、配列に固定されてしまいます。
Dim b : ReDim b(1) としても b は配列になり、後で b に配列以外を格納することもできます。
Redim Preserve a(-1) もできます。
二次元配列は Redim a( 2, 3 ) のようにコンマで区切ります。
{ 1, 2, 3 } のような初期化子はありませんが、a = Array( 1, 2, 3 ) はできます。
空要素を指定したり、階層化することもできます。
ReDim Preserve arr( UBound( arr ) + 1 )
arr( UBound( arr ) ) = 1234
配列のメンバ変数に対する Redim は、メンバ関数の中でしかできません。
返り値を配列にすることはできません。
引数に渡した配列は、関数内で ReDim して要素数を変えることができます。
Dim a, b
a = Array( 1, 2 )
b = a
b = a のように代入すると、すべての配列の要素をコピーします。
C 言語のような参照ではありません。
Dim b() と宣言すると、コピーできなくなります。
関数の返り値に配列を渡すこともできます。
Dim a
a = Array( 1, 2, 3 )
a = Array( )
a = Array( 1 )
a = Array( 1, "ABC" )
a = Array( , "ABC" )
FuncA Array( _
Array( 1, "ABC" ),_
Array( 2, "DEF" ) )
arr
arr
arr
arr
1234
← Array 関数は、配列を返します。
a(0)=1, a(1)=2, a(2)=3, UBound(a)=要素数-1
← 空の配列, UBound(a) = -1
← 要素数が1つの配列
← 数値と文字列が混在した配列
← 空要素を含む配列。 VarType( a(0) ) = vbError
← 配列が入っている配列を関数 FuncA に渡す
配列のメンバ変数に対する Redim は、メンバ関数の中でしかできません。
オブジェクトのメンバを参照するピリオド演算子を使った時点で、Redim した内容は
メンバ変数には反映されません。
ArrayClass(vbslib) を使えば、クラスの外から配列の要素数を変えることができます。
上記のように、1要素ずつ増やすと、処理速度はかなり遅くなります。
←
▼
▲
Dim a, e
a = Split( "abc, 123 ,""ABC""", "," )
For Each e In a : echo "["+ e +"]" : Next
Function Split( Str as stirng, Term as string ) as Array of string
文字列を、指定の文字で区切って、配列に格納します。
【引数】
Str
Term
分割しようとする文字列
区切り文字
返り値
分割した文字列の配列
a(0) = [abc]
a(1) = [ 123 ]
a(2) = ["ABC"]
関連
サンプル
Split( "a,b," ) '// Array( "a", "b", "" )
←
▼
▲
すると、Byte 型の配列が返ります。
バイナリ・ストリームから
VBScript には、バイナリ(Byte 型配列)を作ることはできませんが、ADODB を使うと作れます。
バイナリ・データの一部をリードしたByte 配列は、そのまま
することが
Dim binary '// as Byte()
Dim strbin '// as String
Dim value '// as Integer
value = AscB( binary ) '// 先頭バイトの値
strbin = MidB( binary, 2, 1 ) '// 2バイト目
value = AscB( strbin )
bin = binary(1) '// ( ) を使うとエラー
Dim rf, wf '// as ADODB.Stream
rf.Position = &h10
binary = rf.Read( &h28 )
wf.Write binary '// rf のオフセット &h10 から %h28バイトを wf へ
バイナリの内容を確認するには、AscB と MidB を使います。 AscB 関数だけで、バイナリの
数値を取得できますが、AscB 関数は先頭の文字(バイト)しか数値に変換しないので、多くの
場合で MidB も使うことになります。 ちなみに、MidB の代わりに Byte 配列の配列番号を
使って参照しようとするとエラーになります。
ただし、MidB などの文字列操作関数や + 演算子で返される文字列は、Byte配列ではなく
String 型になるため、 ADODB.Stream の Write に渡すことができません。
AscB や MidB が使えるのは、VBScript が Byte 配列を String 型(文字列)に暗黙的に変換
しているからです。 ただし、VBScript の通常の文字列は、Unicode(2バイト文字)なので、
通常、バイト単位の文字として扱う末尾にBが付いた関数を使います。
ChrB, LeftB, RightB, LenB, StrComp 関数や、+ 演算子などが使えます。
Dim rf, wf '// as ADODB.Stream
binary = rf.Read( adRealAll )
strbin = MidB( binary, &h10, &h28 )
wf.Write strbin '// String 型なのでエラー
できます。 つまり、バイナリ・データの一部を抽出することができます。
strbin = LeftB( binary, 3 ) + ChrB( &h0A ) + RightB( binary, 3 )
ReDim Preverve binary(10)
次のコードはエラーになります。
binary(0)
Byte 配列は、配列を使う関数のうち一部の関数しか使えません。 次の関数は使えます。
Size = UBound( binary ) + 1
LBound( binary ) '// 常に 0
Byte 配列は、( ) を使って配列の要素にアクセスできない代わりに、String 型に暗黙変換
することができるので、文字列を扱う関数を使うことができます。(後述)
VarType( binary ) = vbArray + vbByte = &h2011
つまり、VBScript では、文字列関数や配列機能を使ってバイナリを編集することはできません。
編集するには、ADODB.Stream を活用することで、間接的に編集することができます。
なお、以下に説明する内容は、
まず、バイナリのすべての値 0x00〜0xFF を Unicode を使ってストリームに作成します。
その後、必要に応じて、バイナリを格納する別のストリームに
Dim i, f
Set f = CreateObject( "ADODB.Stream" )
f.Charset = "unicode"
f.Open
'// FE FF 00 01 02 ... FD FE FF
For i=0 To 255 Step 2 : f.WriteText ChrW( i + (i+1)*&h100 ) : Next
f.Position = 0
f.Type = Me.adTypeBinary
f.Position = Values + 2
f2.Position = ...
f.CopyTo f2, 1
f.Close
します。
の内部で使われています。
Dim f1, f2 '// as ADODB.Stream
bin1 = f1.Read( adRealAll )
bin2 = f2.Read( adRealAll )
If StrComp( bin1, bin2, 0 ) = 0 Then echo "same"
Byte 配列を StrComp に渡すことで、バイナリ比較ができます。
文字列のように大小比較もできます。
←
▼
▲
VBScipt は、1つの変数に一般的な変数と配列のどちらでも入れることができます。
これを応用して、1つの値の指定と、複数の値の指定を、1つの変数で対応できます。
Sub main()
Dim a
a = 1 : FuncA a
a = Array( 1, 2, 3 ) : FuncA a
a = Empty : FuncA a
End Sub
下記のように、関数の実際の処理を行う前に配列に統一すると、以降の処理で場合分け
しなくて済みます。
FuncA_sub をわざわざ作っている理由は、下記のように配列を ByVal 引数にすると、
コピーが発生して遅くなってしまうのを避けるためです。
Sub FuncA( ByVal Param ) '// コピーが発生
If not IsArray( Param ) Then Param = Array( Param )
Dim elem
For Each elem In Param
WScript.Echo elem
Next
End Sub
→ ByValArrBench.zip
ByVal 配列のコピーにかかる時間の計測
Sub FuncA( Param )
If IsArray( Param ) Then
FuncA_sub Param
ElseIf IsEmpty( Param ) Then
FuncA_sub Array( )
Else
FuncA_sub Array( Param )
End If
End Sub
Sub FuncA_sub( Param ) '// Param は必ず配列
Dim elem
For Each elem In Param
WScript.Echo elem
Next
End Sub
プロパティに、一般変数と配列変数を設定できるとき、処理を行う前に次のメソッドを
呼び出すと、すべて配列として処理を記述できます。
Public Sub ToStandard()
If IsEmpty( Me.m_PropA ) Then
Me.m_PropA = Array( )
ElseIf not IsArray( Me.m_PropA ) Then
Me.m_PropA = Array( Me.m_PropA )
End If
End Sub
(メモ) Property Set で実現する方法も考えられますが、配列のコピーが入ってしまいます。
Private Sub Class_Initialize()
Me.m_PropA = Array( )
End Sub
Public Property Set PropA( Value )
If IsEmpty( Value ) Then
Me.m_PropA = Array( )
ElseIf not IsArray( Value ) Then
Me.m_PropA = Array( Value )
Else
Me.m_PropA = Value
End If
End Sub
←
▼
▲
If file Is Nothing Then
If IsNull( a ) Then
vbString(=8)
Nothing
Empty
If IsEmpty( file ) Then
Null
vbEmpty(=0)
VarType
-
文字列
Function TypeName( s as variant ) as string
判定文の例
Function VarType( s as variant ) as integer
TypeName
参考
"Empty"
"Nothing"
"Null"
"String"
Class Foo
"Foo"
If IsObject( a ) Then
If TypeName( a ) = "Foo" Then
"Integer"
整数
浮動小数
(倍精度)
"Double"
型
定数(例)
Empty
Nothing
Null
"ABC"
123
1.2
If VarType( a ) = vbString Then
配列
"Variant()"
8024
7
日付
CDate("7/4")
#7/4#
"Date"
If IsDate( a ) Then
new Foo
Array(1,2)
1
vbInteger(=2)
vbDouble(=5)
vbClass(=9)
論理
True,False
vbBoolean(=11)
"Boolean"
If IsNumeric( a ) Then
If VarType( a ) = vbDouble Then
a=Array(,1)
の a(0)
配列の
空要素
"Error"
vbError(=10)
If VarType( a(i) ) = vbError Then
浮動小数
(倍精度)
"Single"
vbSingle(=4)
If IsNumeric( a ) Then
If VarType( a ) = vbSingle Then
関数
Sub/Function
"Object"
vbObject(=9)
If IsObject( a ) Then
If VarType( a ) = vbBoolean Then
← すべての型の一覧
"Byte"
vbByte(=17)
"Long"
vbLong(=3)
0〜255
-32768〜32767, &h0000〜&hFFFF
-2147483648〜2147483647
&h10000〜&hFFFFFFFF
←
▼
▲
Function IsDate( Value as Date or string ) as boolean
Value に指定した値が、Date 型か、日付として有効な文字列かどうかを返します。
←
▼
▲
Function IsNumeric( Value as integer or string ) as boolean
Value に指定した値が、整数型か、浮動小数型か、数字からなる文字列かどうかを返します。
サンプル
IsNumeric( 1 ) = True
IsNumeric( 1.2 ) = True
IsNumeric( "1" ) = True
IsNumeric( "1,000" ) = True
←
▼
▲
関連
は、ありません。
CLng
CSng
CDbl
CStr
FormatCurrency
FormatDateTime
FormatPercent
←
▼
▲
True
= -1 (全ビット1)
False
Not
全ビット反転
= 0
And
Or
全ビット論理積
全ビット論理和
引数に Boolean を指定すると、機能追加により引数が増えてしまうことが多いので、
Flags 型
を使うことをお勧めします。
ビットが1かどうか
ビットが0かどうか
Flags and 4
(Flags and 4)=0
not(Flags and 4) ではありません
←
▼
▲
Option Explicit
Class Book
Public Title ' メンバ変数
Public Price ' メンバ変数
End Class
main
Sub main
Dim book,dic,key,keys
Set book = New Book
book.Title = "Book Title"
book.Price = 400
Set dic = CreateObject( "Scripting.Dictionary" )
dic.Add "key1", book
MsgBox dic.Item("key1").Title
If dic.Exists("key1") Then MsgBox "!"
For Each key in dic.Keys '// or dic.Items
WScript.Echo key & " " & dic.Item(key).Price
Next
dic.Remove "key1"
dic.RemoveAll
End Sub
文字列(Key)から、数値やオブジェクトなど(Item)を高速に引き出します。
Scripting.Dictionary
Remove
RemoveAll
Dictionary
Key は重複できません
要素をデバッガでウォッチするときは、Keys, Items プロパティを参照します。
Key
Key
:
Item
Item
:
Key
Item
Set dic = CreateObject( "Scripting.Dictionary" )
生成
サンプル
関連
Const NotCaseSensitive = 1
Set dic = CreateObject( "Scripting.Dictionary" )
dic.CompareMode = NotCaseSensitive
生成
Key の大文字小文字を区別しない