ある程度のプログラムをしていると、文字列を連結する場面はよくあると思いますが、それが恐ろしく時間がかかるということはないでしょうか?
そんな時に有効な方法です。
MIDステートメントを使って高速化
VBAにはMIDステートメントがあります(MID関数ではないので注意です)。
これを使うことで、文字連結に費やす処理時間を大幅に改善できます。
手順としては下記のとおりです。
1.あらかじめ必要な文字数の文字を変数に埋め込む
(下記は文字列「a」を100個変数に格納した場合)
strChar = VBA.String(100, “a”)
この変数の中をのぞいてみると・・
2.埋め込んだ文字をMidステートメントで入れ替える(置換するイメージ)
(下記は上記の変数を1文字目~10文字目までに右辺の文字を格納)
Mid(strChar, 1, 10) = “あいうえおかきくけこ”
この変数の中をのぞいてみると・・
このように先頭から文字を置換するようなイメージを繰り返します。
実際にテストしてみる
実際に「通常の連結」と「MIDステートメント使用」の違いを見てみます。
Sub 文字列連結でMidステートメントとの比較()
Dim strChar As String
Dim lng As Long
Dim strTime As String
Dim dblTimer As Double
dblTimer = Time
For lng = 1 To 100000
strChar = strChar & “あいうえおかきくけこ”
Next lng
strTime = “通常:” & Time – -dblTimer
Dim lngPos As Long
dblTimer = Time
strChar = VBA.String(10 * 100000, “a”)
lngPos = 1
For lng = 1 To 100000
Mid(strChar, lngPos, 10) = “あいうえおかきくけこ”
lngPos = lngPos + 10
Next lng
strTime = strTime & vbCrLf & “Mid:” & Time – -dblTimer
MsgBox strTime
End Sub
結果はこんな感じでした。驚くほど速いですね。
実務上での可変対応という課題
先のサンプルでは下記のようにあらかじめ必要な文字数の部分で、「入れ替える文字数」と「ループ回数」を入れています。
strChar = VBA.String(10 * 100000, “a”)
しかし実際にはループ回数が可変、格納する文字数も可変だったりするため、事前にどの程度文字を確保しておくのかが難しい場合が多かったりします。
このような場合、(私の場合は)一定の文字数を推測して確保しておきます。
そして処理の途中で、必要に応じて確保する領域を拡大するようにしていします。
For lng = 1 To 100000
Mid(strChar, lngPos, 10) = “あいうえおかきくけこ”
lngPos = lngPos + 10
If UBound(VBA.Split(strChar, “a”)) < 100 Then
strChar = strChar & VBA.String(10 * 100000, “a”)
End If
Next lng
要は残り(変換前)の文字数が何文字かがわかれば、どんな形でもよいと思いますが、このようにして確保した領域が少ない場合に拡張しています。
上記の方法は、文字列を配列化するための時間がかかるため効率的ではなく、lngPosなどで対処したほうが良さそうですが、最近のお気に入りだったので使いました(笑)。
ただし、この場合だと今度はループ終了後に変換されなかった文字が余る場合も出てきます。そのため最後の処理で必要な文字列にしています。また文字数を確保するために使用した「a」という文字も実際には使われてない文字(空白)などにするほうが都合がよい場合もありいます。それに合わせた形で下記のようにしています。
strChar = VBA.Replace(strChar, “a”, “”)