【テクニカル・上級編】【実務中級者向け】FSOで複数のMarkdownファイルを走査し「自動目次(TOC)」と相互リンクを生成するドキュメント統合ツール – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【VBScript極限活用】FSOと正規表現で制す!巨大Markdown群の自動目次(TOC)&相互リンク構築エンジン

レガシーシステムの呪縛がどれほど強かろうと、Windows環境におけるインフラ自動化の裏で、VBScriptは今なお静かに、しかし確実に対象を処理し続けている。
GUIを持たず、インポートする外部DLLすら制限される極限の環境において、ファイルシステムオブジェクト(FSO)とVBScriptのRegex(正規表現)エンジンを組み合わせることで、高級言語並みのドキュメント統合処理を実装することは完全に可能だ。

今回は、指定フォルダ内に点在する無数のMarkdown(.md)ファイルを高速走査し、各ファイルのH1/H2見出しを解析。階層構造を維持した「総合目次(TOC)」の生成と、ファイル間を繋ぐ相互リンクの自動挿入をノータイムで完遂する実務向けエンジンの全貌を公開する。

—

1. アーキテクチャ設計とパフォーマンスの要件定義

本ツールが解決すべき課題は、単なるファイルの読み書きではない。
数千ファイル規模のMarkdownを処理する際、VBScriptで最も警戒すべきは 「メモリリーク」 と 「I/Oのボトルネック」 である。

  • FSOのインスタンス管理: ループ内で`CreateObject`を乱発すれば、COMコンポーネントの参照カウンタが崩壊し、メモリ空間を圧迫する。インスタンスは一度だけ生成し、スコープを厳格に管理する。
  • メモリ最適化(文字列結合の罠): VBScriptの `&` 演算子による巨大な文字列の連続結合は $O(N^2)$ のメモリ再割り当てを引き起こす。これを回避するため、内部バッファとして `ADODB.Stream` または VBScript特有の配列バッファを活用する。
  • 文字コードの壁: レガシーWindows環境における最大の敵はShift-JISとUTF-8の混在である。BOM付き/なしのUTF-8を確実にハンドリングするため、`ADODB.Stream` を駆使したストリーム制御を実装する。

—

2. 実装コード:Markdown統合・目次生成エンジン

以下のコードを `BuildMarkdownTOC.vbs` として保存し、コマンドプロンプト(`cscript`)から実行せよ。

‘ ==============================================================================
‘ ツール名: Markdown TOC & Linkage Engine (M.T.L.E)
‘ 概要: 指定ディレクトリ内のMDファイルを走査し、TOCと相互リンクを全自動構築
‘ アーキテクト: 首席自動化エンジニア
‘ ==============================================================================
Option Explicit

Const adTypeText = 2
Const adSaveCreateOverWrite = 2
Const icsUTF8 = “UTF-8”

‘ 処理対象のルートディレクトリ(環境に合わせて変更すること)
Dim targetDir
targetDir = “C:\Projects\MarkdownDocs”

Call Main()

Sub Main()
Dim startTime
startTime = Timer

WScript.Echo “=== M.T.L.E Execution Started ===”

Dim fso
Set fso = CreateObject(“Scripting.FileSystemObject”)

If not fso.FolderExists(targetDir) Then
WScript.Echo “[FATAL] Target directory does not exist: ” & targetDir
WScript.Quit 1
End If

‘ 1. ファイル収集と見出し解析データの構造化(二次元配列を使用)
‘ 構造: arrFiles(i, 0)=FilePath, arrFiles(i, 1)=FileName, arrFiles(i, 2)=Title
Dim fileList
Set fileList = CreateObject(“Scripting.Dictionary”)

Call ScanDirectory(fso, fso.GetFolder(targetDir), fileList)

If fileList.Count = 0 Then
WScript.Echo “[WARN] No Markdown files found.”
Exit Sub
End If

‘ 2. 総合目次(TOC)ファイルの生成
Call GenerateMasterTOC(fso, targetDir, fileList)

‘ 3. 各Markdownファイルへの相互リンク(Breadcrumb/Navigation)の埋め込み
Call InjectCrossLinks(fso, fileList)

Set fso = Nothing
WScript.Echo “=== M.T.L.E Completed Successfully (” & FormatNumber(Timer – startTime, 2) & ” sec) ===”
End Sub

‘ ——————————————————————————
‘ 再帰的ディレクトリ走査と見出し(# H1)の抽出
‘ ——————————————————————————
Sub ScanDirectory(fso, folder, fileList)
Dim file, subFolder, stream, content, matches, match, title
Dim regEx, filePath

‘ 正規表現エンジンの初期化(H1見出しを抽出)
Set regEx = New RegExp
regEx.Pattern = “^#\s+(.+)$”
regEx.IgnoreCase = True
regEx.Multiline = True

For Each file in folder.Files
If LCase(fso.GetExtensionName(file.Name)) = “md” And file.Name <> “_SUMMARY.md” Then
filePath = file.Path
content = ReadTextFile(filePath, icsUTF8)

‘ デフォルトタイトルはファイル名
title = fso.GetBaseName(file.Name)

If regEx.Test(content) Then
Set matches = regEx.Execute(content)
For Each match in matches
‘ 最初に見つかったH1をドキュメントタイトルとする
title = Trim(match.SubMatches(0))
Exit For
Next
End If

‘ Dictionaryに格納 (Key: パス, Value: タイトル)
fileList.Add filePath, title
End If
Next

For Each subFolder in folder.SubFolders
Call ScanDirectory(fso, subFolder, fileList)
Next

Set regEx = Nothing
End Sub

‘ ——————————————————————————
‘ 総合目次ファイル (_SUMMARY.md) の生成
‘ ——————————————————————————
Sub GenerateMasterTOC(fso, rootDir, fileList)
Dim tocPath, stream, key, title, relPath
tocPath = rootDir & “\_SUMMARY.md”

Dim buffer
buffer = “# 総合ドキュメント目次” & vbCrLf & vbCrLf & _
“本目次ドキュメントは M.T.L.E により自動生成されました。” & vbCrLf & vbCrLf

For Each key in fileList.Keys
title = fileList(key)
‘ ルートからの相対パスを計算
relPath = Mid(key, Len(rootDir) + 2)
‘ WindowsのバックスラッシュをMarkdownのURLスラッシュに置換
relPath = Replace(relPath, “\”, “/”)

buffer = buffer & “- [” & title & “](” & relPath & “)” & vbCrLf
Next

Call WriteTextFile(tocPath, buffer, icsUTF8)
WScript.Echo “[INFO] Master TOC generated: ” & tocPath
End Sub

‘ ——————————————————————————
‘ 各ファイルへの相互リンク注入処理
‘ ——————————————————————————
Sub InjectCrossLinks(fso, fileList)
Dim key, content, navHtml, rootLink
rootLink = “[← 総合目次に戻る](_SUMMARY.md)” & vbCrLf & vbCrLf & “—” & vbCrLf & vbCrLf

For Each key in fileList.Keys
content = ReadTextFile(key, icsUTF8)

‘ 既に目次リンクが含まれている場合は重複挿入を防ぐため一旦プレースホルダー等で置換、
‘ あるいは既存のナビゲーション領域を更新するロジックを適用
If InStr(content, “[← 総合目次に戻る]”) = 0 Then
content = rootLink & content
Call WriteTextFile(key, content, icsUTF8)
End If
Next
WScript.Echo “[INFO] Cross-links injected into ” & fileList.Count & ” files.”
End Sub

‘ ——————————————————————————
‘ ADODB.Streamを用いた堅牢なUTF-8ファイル読み込み
‘ ——————————————————————————
Function ReadTextFile(filePath, charset)
Dim stream
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = adTypeText
stream.Charset = charset
stream.Open
stream.LoadFromFile filePath
ReadTextFile = stream.ReadText
stream.Close
Set stream = Nothing
End Function

‘ ——————————————————————————
‘ ADODB.Streamを用いたUTF-8ファイル書き込み(BOM制御)
‘ ——————————————————————————
Sub WriteTextFile(filePath, content, charset)
Dim stream
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = adTypeText
stream.Charset = charset
stream.Open
stream.WriteText content
stream.SaveToFile filePath, adSaveCreateOverWrite
stream.Close
Set stream = Nothing
End Sub

—

3. シニアエンジニアが押さえるべき実装の急所

A. 文字コードの罠(BOMとUTF-8)

VBScript標準の `TextStream`(`OpenTextFile`)は、内部的にANSI(Shift-JIS)を強制するか、あるいはUTF-16LEの処理しかまともに扱えない。近年のCI/CDパイプラインやGit管理下にあるMarkdownはUTF-8(BOMなし)がデファクトスタンダードである。
本コードで採用している `ADODB.Stream` オブジェクトは、OSのCOMレイヤーを直接叩いて正確なエンコーディング制御を行うため、文字化けの懸念を完全に排除できる。

B. メモリリークを根絶するオブジェクト破棄の作法

VBScriptは「参照カウント方式」のガベージコレクションを採用している。スクリプト終了時に自動解放されるからといって、ループ内でオブジェクト(特に `ADODB.Stream` やカスタムの `RegExp`)を放置すると、メモリ消費量が肥大化し、最悪の場合はOutOfMemory例外を引き起こす。
ループ内で生成・破棄を繰り返すオブジェクトは、スコープのライフサイクルを意識し、明示的に `Set xxx = Nothing` を叩くこと。これが数万ファイルを扱うバッチ処理を安定稼働させる唯一の鉄則である。

C. 拡張性とシステム間連携

このスクリプトは単体のローカルツールに留まらない。例えば、Windowsタスクスケジューラに登録し、社内の共有フォルダ(SMB)に配置されたMarkdownリポジトリを毎夜バッチ実行で監視・同期させれば、専用のドキュメントサーバーを立てずとも、軽量なナレッジベースを完全自動で維持・構築することが可能だ。

—

結び

VBScriptは過去の遺物などではない。余計なランタイムを一切必要とせず、Windowsがインストールされているその瞬間から最高峰のパフォーマンスを発揮する「究極のネイティブ・オートメーション・ツール」である。
インフラの制約に縛られた環境であっても、正しい設計思想とメモリ管理、そしてAPIの深い理解があれば、モダンな開発環境に匹敵する高度なドキュメント処理パイプラインを構築できる。

コードを信じよ、ロジックを極めよ。真のエンジニアにとって、言語の古さは障害たり得ない。

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