【実務・中級編】【高度な配列操作】Filter 関数と Join / Split の組み合わせによる要素の超高速絞り込みと一括整形 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを極めよ:`Filter`・`Split`・`Join`の三位一体で実現する超高速配列絞り込み術

業務自動化の現場において、VBScript(WSH)は依然としてレガシーシステムとの統合やクライアント端末のキッティング、簡易的なバッチ処理において現役で稼働し続けている。
しかし、多くのプログラマ(あるいは非プログラマの業務担当者)が書くVBScriptのコードは、致命的な非効率を抱えている。

その最たるものが 「配列の要素を舐めるための `For…Next` ループの多用」 だ。

数千行、数万行のテキストデータを読み込み、1行ずつ条件分岐(`If`)で判定して別配列に再格納する――このような愚直なコードは、VBScriptのインタプリタの特性上、実行速度を著しく低下させる。メモリの再割り当て(`ReDim Preserve`)をループ内で繰り返そうものなら、GC(ガベージコレクション)とメモリウムの嵐で処理は完全にフリーズする。

今回は、VBScriptの標準関数である `Filter`、`Split`、`Join` を極限まで組み合わせ、ループ処理を排除した「超高速な配列操作と一括整形」のデザインパターンを伝授する。

なぜ `For` ループによる配列走査は悪なのか?

VBScriptの配列(特に動的配列)は、内部的にCOMのバリアント型(`SAFEARRAY`)として管理されている。
`ReDim Preserve` を実行するたびに、システムはメモリ上の新しい領域を確保し、既存のデータを丸ごとコピーするという高コストな処理を行っている。

これをループのたびに実行するコードは、時間計算量(オーダー)が最悪の形になり、実務で扱うデータ量には耐えられない。

我々が目指すべきは、「VBScriptの内部C++層に処理を丸投げし、スクリプト層でのループを極限までゼロにする」 ことだ。そのための切り札が、文字列を高速に解体・結合・抽出するこの3つの関数である。

三大関数の本質的理解

1. `Split(Expression, [Delimiter])`

巨大な文字列を一撃で1次元配列に変換する。メモリ上の連続した領域にトークンを展開するため、ファイル読込後のパースにおいて `For` ループで1文字ずつ処理するよりも圧倒的に高速。

2. `Filter(SourceArray, Match, [Include], [Compare])`

本記事の主役。 配列の中から特定の文字列を含む(または含まない)要素を一瞬で抽出し、新たな1次元配列として返す。この関数自体が内部でCレベルの高速検索を行っているため、スクリプト側で `If InStr(…)` を回す必要が一切なくなる。

3. `Join(SourceArray, [Delimiter])`

配列の全要素を指定の区切り文字で結合し、一つの文字列に戻す。データベースへのバルクインサート用クエリの生成や、CSV形式への一括変換において神速を発揮する。

実践:プロダクションコード(堅牢なログ解析・絞り込みツール)

以下のコードは、数万行のログファイルから特定のステータス(例: “ERROR”)を持つ行だけを抽出し、フォーマットを整えて別ファイルに出力する実務想定のスクリプトだ。
エラーハンドリング(`On Error Resume Next` の正しい封じ込め)と、メモリ枯渇を防ぐ堅牢な設計を実装している。

Option Explicit

‘ ==============================================================================
‘ スクリプト名: HighSpeedLogExtractor.vbs
‘ 概要: 巨大なテキストログから特定キーワードを高速抽出し、一括整形する
‘ アーキテクチャ: Loopless Filtering & Batch Formatting Pattern
‘ ==============================================================================

Sub Main()
Dim fso, targetPath, outputPath
Set fso = CreateObject(“Scripting.FileSystemObject”)

targetPath = fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName), “server_access.log”)
outputPath = fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName), “error_summary.csv”)

‘ ファイルが存在しない場合は早期リターン
If Not fso.FileExists(targetPath) Then
WScript.Echo “致命的エラー: 対象のログファイルが見つかりません。” & vbCrLf & targetPath
Exit Sub
End If

Dim startTime
startTime = Timer

‘ 1. ファイル全体を「一撃」でメモリ上に読み込む (Readall)
Dim fileStream, rawData
Set fileStream = fso.OpenTextFile(targetPath, 1, False) ‘ 1 = ForReading
rawData = fileStream.ReadAll
fileStream.Close
Set fileStream = Nothing

‘ 2. 改行コード(vbCrLf / vbLf)を統一し、Splitで一気に配列化
‘ ※環境依存の改行コード揺れを吸収する前処理
rawData = Replace(rawData, vbCrLf, vbLf)
rawData = Replace(rawData, vbCr, vbLf)

Dim allLines
allLines = Split(rawData, vbLf)

‘ 3. 【核心】Filter関数によるループレス絞り込み
‘ “ERROR” という文字を含む要素だけを抽出した新しい配列を一瞬で生成
Dim errorLines
errorLines = Filter(allLines, “ERROR”, True, 1) ‘ 1 = 比較モード(大文字小文字を区別しない場合は vbTextCompare)

‘ 抽出結果が0件だった場合のガード処理
If UBound(errorLines) < LBound(errorLines) Then WScript.Echo "対象となるエラー行は見つかりませんでした。" Exit Sub End If ' 4. 【整形】Join と Split / Replace の応用による一括加工 ' ここでは抽出されたログ配列に対し、タブ区切りをカンマ区切りに置換しつつ一括変換する ' 配列のままループを回さず、一度Joinして文字列化 -> 置換 -> 再Splitというアプローチも有効
Dim joinedErrors
joinedErrors = Join(errorLines, vbCrLf)

‘ 例: 特定の不要な文字列を一括削除(正規表現を使わずとも高速)
joinedErrors = Replace(joinedErrors, “[INTERNAL_SERVER]”, “[SYS]”)

‘ 5. 結果を一括書き込み
Dim outStream
Set outStream = fso.CreateTextFile(outputPath, True, False) ‘ True = 上書き, False = ASCII/ANSI
outStream.Write joinedErrors
outStream.Close
Set outStream = Nothing

Dim elapsedTime
elapsedTime = Timer – startTime

WScript.Echo “処理完了: ” & (UBound(errorLines) + 1) & “件のエラーを抽出しました。” & vbCrLf _
& “実行時間: ” & FormatNumber(elapsedTime, 4) & ” 秒” & vbCrLf _
& “出力先: ” & outputPath

Set fso = Nothing
End Sub

‘ 実行
Main()

ヴイ・ビー・スクリプトにおけるプロフェッショナルな設計とは、「いかにVBScriptに自前でループを回させないか」に尽きる。

データベース(ADODB.Recordset)からのデータ抽出や、CSVのバルク処理においても、この `Split` / `Filter` / `Join` のパイプライン思考を取り入れることで、VBScriptとは思えないほどの爆速な自動化ツールを構築することが可能だ。

レガシーな技術であっても、背後にあるメモリ構造と関数の特性を深く理解していれば、モダンな言語に匹敵するパフォーマンスを引き出すことができる。現場の武器として、ぜひこのイディオムをマスターしてほしい。

タイトルとURLをコピーしました