—
【VBScript極限奥義】コンソール出力を支配せよ:Shift-JIS文字幅を完全掌握するプロフェッショナルなアライメント設計
業務自動化の最前線において、VBScript(WSH)はいまだに現役の強力な武器だ。しかし、多くのエンジニアが「コンソール画面(CScript)への美しき表形式出力」という壁にぶち当たり、そして敗北していく。
理由は明白。VBScriptの標準関数には、日本語環境における「文字の視覚的幅(全角2、半角1)」を正確に算出する機能が欠落しているからだ。
単なる `Len()` 関数は文字数を返し、`LenB()` はUnicodeとしての内部バイト数を返す。これでは、マルチバイト文字が混在した瞬間に、丹精込めて設計したレポートの列は無残に崩れ去る。
今回は、私が数多のミッションクリティカルな現場で実装してきた、「Shift-JIS換算での正確な文字幅算出」と、それを用いた「絶対に崩れないテキスト整形」の極意を伝授する。
—
1. なぜあなたの `Len()` は嘘をつくのか
VBScriptの内部文字列はすべて UTF-16(Unicode) だ。
例えば、「A」(半角)も「あ」(全角)も、`Len()` で測ればどちらも「1文字」である。
「ならば `LenB()` を使えばいい」と考える初級者がいるが、それはさらなる泥沼への入り口だ。UTF-16において、すべての基本文字は2バイトとして扱われる。つまり `LenB(“A”)` も `LenB(“あ”)` も、共に「2」を返す。これではコンソール上の表示幅(1:2)を制御する指標にはなり得ない。
我々が求めるのは、「Windowsコンソールの標準エンコーディング(多くの場合 CP932/Shift-JIS)におけるバイト数」だ。これこそが、コンソールのセル幅に直結する唯一の正解である。
—
2. 極限の文字幅算出ロジック: `GetDisplayWidth`
VBScriptにはVBAの `StrConv` のような便利な変換関数が存在しない。そこで、各文字の文字コードを評価し、それが「半角(1幅)」の範囲に収まるか、「それ以外(全角2幅)」かを判定するロジックを構築する。
プロダクション・グレードの実装
以下のコードは、パフォーマンスと堅牢性を両立させた設計だ。
‘
‘ 関数名:GetDisplayWidth
‘ 概要 :文字列の表示幅(半角1、全角2)を正確に算出する
‘ 引数 :strTarget – 対象文字列
‘ 戻り値:合計表示幅(整数)
‘
Function GetDisplayWidth(ByVal strTarget)
Dim nWidth, nLen, i, c, code
nWidth = 0
‘ Null または空文字のガード
If IsNull(strTarget) Or strTarget = “” Then
GetDisplayWidth = 0
Exit Function
End If
nLen = Len(strTarget)
For i = 1 To nLen
c = Mid(strTarget, i, 1)
code = Asc(c)
‘ Shift-JIS換算での判定ロジック
‘ 0~255(半角英数、制御文字)および
‘ 0xFF61~0xFF9F(いわゆる半角カナ)を1幅とする
‘ ※Asc関数が負の値を返す場合は全角確定
If (code >= 0 And code <= 255) Then
nWidth = nWidth + 1
Else
' Unicode上の半角カナ判定が必要な場合はここで拡張
' 通常のAsc関数で判定不可能な特殊文字への耐性を持たせる
nWidth = nWidth + 2
End If
Next
GetDisplayWidth = nWidth
End Function
---
3. 実践:絶対に崩れない「パディング関数」の構築
幅を算出できるだけでは不十分だ。算出した幅に基づき、動的に空白を補完する「パディング(穴埋め)」の技術が、プロフェッショナルなUIを完成させる。
‘
‘ 関数名:PadRightCustom
‘ 概要 :全角半角を考慮し、指定した幅になるよう右側にスペースを補完する
‘
Function PadRightCustom(ByVal strText, ByVal nTotalWidth)
Dim currentWidth, nNeeded
If IsNull(strText) Then strText = “”
currentWidth = GetDisplayWidth(strText)
nNeeded = nTotalWidth – currentWidth
If nNeeded > 0 Then
PadRightCustom = strText & Space(nNeeded)
Else
‘ 指定幅を超えている場合は、切り出しロジックを検討すべきだが
‘ ここでは安全のためそのまま返す
PadRightCustom = strText
End If
End Function
—
4. 業務ツールへの統合:データベース・CSV連携の注意点
実務において、この関数をどこで呼ぶべきか。アーキテクトの視点から言えば、「出力の直前(Presentation Layer)」に限定すべきだ。
1. データベース(ADODB)からの取得時:
DB上のデータは型が厳密だ。`Null` が混入することを前提に、必ず `GetDisplayWidth(CStr(rs(“Column”)))` のように型変換を噛ませる。
2. ファイルシステム(FileSystemObject)との連携:
読み込んだCSVデータの各フィールドに対してこの関数を適用し、コンソールに流し込む。
3. パフォーマンスの最適化:
数万行のデータをループで回す際、毎回関数を呼ぶコストが気になるなら、`Dictionary` オブジェクトに一度計算した文字の幅をキャッシュする戦略(メモ化)も有効だが、WSHの実行速度であれば数千行程度なら直列処理で全く問題ない。
—
5. 黄金の実行例:美しき表形式出力
さあ、準備は整った。以下のコードで、実際に表を出力してみよう。
‘ メイン処理例
Dim data(2, 2)
data(0, 0) = “ID” : data(0, 1) = “商品名” : data(0, 2) = “価格”
data(1, 0) = “A001” : data(1, 1) = “ノートパソコン(Pro)” : data(1, 2) = “120,000”
data(2, 0) = “B999” : data(2, 1) = “高級な林檎” : data(2, 2) = “500”
Dim i, line
WScript.Echo “——————————————”
For i = 0 To 2
line = “|” & PadRightCustom(data(i, 0), 6) _
& “|” & PadRightCustom(data(i, 1), 20) _
& “|” & PadRightCustom(data(i, 2), 10) & “|”
WScript.Echo line
Next
WScript.Echo “——————————————”
実行結果のイメージ
——————————————
|ID |商品名 |価格 |
|A001 |ノートパソコン(Pro) |120,000 |
|B999 |高級な林檎 |500 |
——————————————
半角カナ(1幅)と全角(2幅)が混在しても、パイプライン(`|`)の位置が完璧に揃っていることに注目してほしい。
—
結論:細部への拘りがツールの信頼性を生む
「たかがコンソールの見た目」と切り捨てる者は、いずれ大規模なシステム統合でも「データの整合性」という細部を見落とす。
今回紹介した `GetDisplayWidth` は、VBScriptという枯れた技術の中で、Windowsの文字コード体系という深い歴史と対峙するための知恵だ。この関数をあなたの「秘伝のライブラリ」に加え、現場のオペレーターが「使いやすい」と唸る、堅牢で美しいツールを提供し続けてほしい。
これが、プロフェッショナルな自動化エンジニアとしての矜持である。
