【テクニカル・上級編】【コンソール表示レイアウト崩れ防止】マルチバイト文字の表示幅判定と自作Padding関数によるマルチ列揃え – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

コンソールの美学:VBScriptにおけるマルチバイト混在文字列の完全な桁揃え制御

諸君、コンソール出力の「ズレ」に頭を抱えたことはないか。

Windows Script Host (WSH) で `CScript` を叩く際、`WScript.StdOut.Write` で出力される文字列が、全角・半角混在によって無惨に崩れる光景は、現場を知る者にとって耐えがたい屈辱だ。これは単なる見た目の問題ではない。ログの可読性を損なうことは、障害解析のスピードを鈍らせることに直結するからだ。

今回は、VBScriptというレガシーな枠組みの中で、いかにしてマルチバイト文字の表示幅を計算し、完璧なレイアウトを構築するか。その極限の知見を授ける。

なぜ `Len()` 関数では不十分なのか

VBScriptの `Len()` 関数は、あくまで「文字の個数」しか数えない。しかし、コンソールのレンダリングエンジンは、伝統的に「全角=2文字分、半角=1文字分」の幅で表示する。

ここで多くの初心者が陥る罠が、`LenB()` の誤用だ。`LenB()` は文字のバイト数を返す。Shift-JIS環境であれば全角は2バイト、半角は1バイトだが、Unicode内部表現を扱うVBScriptでは、この挙動が環境依存やサロゲートペアの扱いで安定しない。

真の解決策は、「目視上の表示幅(Display Width)」をロジックで再定義することにある。

核心:表示幅計算エンジンとPadding関数

以下に示すのは、私が長年、基幹システムのバッチ処理で使い回してきた「表示幅判定」と「パディング」のモジュールだ。これを使えば、どのような混在テキストでも、ピクセル単位ならぬ「文字グリッド単位」で完璧な制御が可能となる。

‘——————————————————————————-
‘ コンソール出力用:マルチバイト対応パディングモジュール
‘ @param str 対象の文字列
‘ @param width 揃えたい総幅(半角換算)
‘ @param align 0:左寄せ, 1:右寄せ
‘——————————————————————————-
Function PadString(str, width, align)
Dim i, charCode, displayWidth, char
displayWidth = 0

‘ 1. 表示幅の計算(全角は2、半角は1と定義)
For i = 1 To Len(str)
charCode = Asc(Mid(str, i, 1))
‘ Ascで取得した値が負数または256以上なら全角とみなす(Shift-JIS/Unicode判定)
If charCode < 0 Or charCode > 255 Then
displayWidth = displayWidth + 2
Else
displayWidth = displayWidth + 1
End If
Next

‘ 2. 不足分のスペースを生成
Dim paddingLen
paddingLen = width – displayWidth
If paddingLen < 0 Then paddingLen = 0 Dim paddingStr paddingStr = String(paddingLen, " ") ' 3. アライメント処理 If align = 0 Then PadString = str & paddingStr ' 左寄せ Else PadString = paddingStr & str ' 右寄せ End If End Function ' 使用例 WScript.StdOut.WriteLine PadString("ステータス", 15, 0) & " | 完了" WScript.StdOut.WriteLine PadString("処理ID", 15, 0) & " | 0001" ---

アーキテクトの視点:メモリとライフサイクル

VBScriptはインタープリタ型言語であり、ガベージコレクションの挙動は決して高速とは言えない。特に数万行のログを出力するバッチ処理において、文字列結合を繰り返すのは愚の骨頂だ。

1. 文字列連結の最適化

VBScriptでは `&` 演算子による連結は、メモリ再確保を伴うためパフォーマンスを悪化させる。もし頻繁に巨大なテキストを構築する場合は、`System.Text.StringBuilder` のように、一旦配列に格納し `Join()` 関数で一括結合する手法を検討せよ。

2. オブジェクトの明示的解放

`Set obj = Nothing` を忘れるな。スクリプトが短命であればOSが回収するが、長時間稼働する常駐プロセスや大規模バッチでは、メモリリークは「死」を意味する。特にWMIオブジェクトやADODB接続を使用する場合は、必ず `Finally` ブロックに近い感覚で明示的に解放する規律を持つことだ。

3. 環境依存文字の排除

`Asc()` 関数はShift-JISを前提としている。もし環境が完全にUTF-8で統一されている場合、あるいはサロゲートペア(絵文字等)が含まれる可能性がある場合は、`ADODB.Stream` を使用してバイナリレベルで文字コードを変換し、正確な幅を測定する必要がある。だが、社内業務システムであれば、まずは上記のロジックで十分に対応可能だ。

結論:技術は「美」に宿る

コンソールの出力結果は、システム開発者の品格そのものだ。

「動けばいい」という考えは捨てよ。Shift-JISの制約を受け入れるのではなく、その制約を逆手に取り、計算し尽くされた出力を提供する。それこそが、レガシー環境を支配するエンジニアの矜持である。

このモジュールを各自のライブラリに組み込み、混沌としたログの海に秩序をもたらしてほしい。質問があればいつでも受け付ける。ただし、基礎的なマニュアルに載っているようなことは自分で調べろ。我々には、やるべきことが山ほどあるのだから。

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