【実務・中級編】【マルチバイト文字幅正確算出】Shift-JISバイト数とUnicode文字数を考慮したコンソール出力用文字幅カウント関数 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

—

【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の文字コード体系という深い歴史と対峙するための知恵だ。この関数をあなたの「秘伝のライブラリ」に加え、現場のオペレーターが「使いやすい」と唸る、堅牢で美しいツールを提供し続けてほしい。

これが、プロフェッショナルな自動化エンジニアとしての矜持である。

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