こんにちは! VBScriptの世界へようこそ。
マクロの記録ボタンを押すだけの世界から一歩踏み出し、自らの手でWindowsを自在に操る自動化の脚本(スクリプト)を書こうとしているあなたを、私は心から歓迎します。
さて、業務の現場で避けて通れないのが「CSVファイルの生成」です。
「なんだ、カンマで区切ってテキストとして書き出せばいいだけ簡単簡単!」……そう思って油断していませんか?
もし、エクスポートするデータの中に「カンマ(,)」や「改行」、そして「ダブルクォーテーション(”)」が混ざっていたらどうなるでしょう。Excelで開いたときに列が盛大にズレたり、データが行方不明になったりして、システム部門のチャットが青ざめた顔のスタンプで埋め尽くされることになります。
今回は、RFC 4180(CSVの標準仕様)に完全準拠し、どんな凶悪な文字列が来ても絶対にCSVを壊さない「プロ仕様の安全なCSVエスケープ関数」を一緒に作っていきましょう。ここをクリアすれば、あなたのVBScriptのスキルは間違いなく一段階上のステージに到達しますよ!
—
1. なぜCSVのエスケープ処理で現場は泣くのか?
VBScriptでCSVを出力するとき、私たちは通常 `Scripting.FileSystemObject` を使ってテキストファイルに文字を書き込みます。
例えば、こんなデータを書き出したいとします。
> 商品名:`超・高速USBケーブル, (1.5m)` (カンマが含まれている)
> 備考:`彼は言った。「これは買いだ!」と。` (ダブルクォーテーションが含まれている)
素朴なプログラミング初心者がやりがちな書き方はこうです。
‘ 【危険なアンチパターン】絶対に真似してはいけない例
Dim textLine
textLine = productName & “,” & memo
‘ → 超・高速USBケーブル, (1.5m),彼は言った。「これは買いだ!」と。
これをExcelで開くとどうなるか。カンマが「区切り文字」として認識されてしまい、本来1つのセルに入ってほしいデータが、勝手に3つや4つのセルに分裂してしまいます。これが現場で「データが壊れた!」と騒ぎになる原因の正体です。
—
2. RFC 4180が定める「CSVの鉄則」
世界共通のルールである RFC 4180 では、データ内に特殊文字が含まれている場合、以下の鉄則を守るべきと定めています。
1. フィールド全体をダブルクォーテーション (`”`) で囲む
データの中にカンマや改行、ダブルクォーテーションが含まれている場合、そのフィールドの最初と最後に `”` を付けます。
2. データ内のダブルクォーテーションは「2つ重ねる」
これが一番のトラップです。データの中に `”` がある場合、それを `””`(二重引用符)に置換してエスケープしなければ、囲み文字のペアが崩れてしまいます。
このルールをVBScriptの文字列操作関数(`Replace`など)を使って美しく実装するのが今回のミッションです。
—
3. 実装:完全準拠の安全なCSVエスケープ関数
それでは、実際のコードを見てみましょう。
メモ帳に貼り付けて拡張子を `.vbs` にすれば、すぐにあなたのPCで実行できます。
Option Explicit
‘ =================================================================0
‘ メイン処理
‘ =================================================================0
Dim sampleText1, sampleText2, sampleText3
Dim escaped1, escaped2, escaped3
‘ テストケースの準備
sampleText1 = “通常テキストです”
sampleText2 = “商品A, 特価品” ‘ カンマを含む
sampleText3 = “彼氏「おいおい、””マジかよ””?」と言った” ‘ ダブルクォーテーションを含む
‘ エスケープ関数に通す
escaped1 = EscapeCsvField(sampleText1)
escaped2 = EscapeCsvField(sampleText2)
escaped3 = EscapeCsvField(sampleText3)
‘ 結果をコンソールに表示(WScript.Echo)
WScript.Echo “元データ1: ” & sampleText1 & vbCrLf & “変換後: ” & escaped1 & vbCrLf
WScript.Echo “元データ2: ” & sampleText2 & vbCrLf & “変換後: ” & escaped2 & vbCrLf
WScript.Echo “元データ3: ” & sampleText3 & vbCrLf & “変換後: ” & escaped3 & vbCrLf
‘ =================================================================0
‘ 関数名: EscapeCsvField
‘ 概要: RFC 4180に準拠し、CSVのセル内文字列を安全にエスケープする
‘ 引数: strValue (String) – エスケープ対象の文字列
‘ 戻り値: String – エスケープ済みの文字列
‘ =================================================================0
Function EscapeCsvField(ByVal strValue)
‘ 1. 値がNullやEmptyの場合は、空文字として安全に処理する
If IsNull(strValue) Or IsEmpty(strValue) Then
EscapeCsvField = “”
Exit Function
End If
‘ 2. 文字列型に明示的に変換
Dim val
val = CStr(strValue)
‘ 3. 【最重要】データ内のダブルクォーテーション(“)を、2つ重ねる(“”)に置換する
‘ VBScriptのReplace関数: Replace(対象, 検索文字列, 置換文字列)
val = Replace(val, “”””, “”””””)
‘ 4. データ内に「カンマ(,)」「ダブルクォーテーション(“”)」「改行(vbCr, vbLf)」の
‘ いずれかが含まれているかチェックする
If InStr(val, “,”) > 0 Or _
InStr(val, “”””) > 0 Or _
InStr(val, vbCr) > 0 Or _
InStr(val, vbLf) > 0 Then
‘ 含まれている場合は、全体をダブルクォーテーションで囲む
val = “””” & val & “”””
End If
‘ 5. エスケープ済みの値を返す
EscapeCsvField = val
End Function
—
4. コードの深掘り・ここがエンジニアの腕の見せ所
初心者の方が「おっ」と思うポイントや、VBScript特有の罠をいくつか解説しておきますね。
① ダブルクォーテーションの表現 (`””””`)
VBScriptのコード内でダブルクォーテーション自体を文字列リテラルとして書くとき、文字を `”` で挟む仕様上、エスケープとして `””` と書く必要があります。
さらにそれを「置換元の文字」として渡すために、VBScriptではなんと `””””`(4つ連続) と書かなければなりません。
- `”` (文字列の開始)
- `””` (エスケープされた1つのダブルクォーテーション)
- `”` (文字列の終了)
……というパズル構造になっています。最初は頭がクラッとしますが、これが書けるようになるとVBScriptの文字列マスターに一歩近づきます。
② `ByVal` による値渡しの安全性
関数定義の `Function EscapeCsvField(ByVal strValue)` に注目してください。
VBScriptのデフォルトは `ByRef`(参照渡し)ですが、関数内で引数の変数を書き換える可能性がある場合や、思わぬ副作用を防ぐために、明示的に `ByVal`(値渡し)を指定するのが、堅牢なコードを書くプロの作法です。
③ 空値(Null / Empty)への配慮
実務のデータベースから引っ張ってきた値には、しばしば `Null` が混ざっています。これをそのまま `CStr()` や `Replace()` に放り込むと、VBScriptは容赦なく 「実行時エラー:プロシージャの呼び出し、または引数が不正です (Error 5)」 を吐いてスクリプトを強制終了させます。
関数の冒頭で `IsNull` や `IsEmpty` を弾くガード節を入れているのは、そのためです。
—
5. おわりに:ここをクリアすれば基本はバッチリ!
いかがでしたでしょうか?
今回は、単なる「文字の置き換え」に留まらず、標準仕様(RFC 4180)に裏打ちされた堅牢なエスケープ関数を構築しました。
業務自動化の世界では、「動けばいいや」で作られたコードは、データ量が増えたり、ユーザーが変な文字を入力したりした瞬間に必ず崩壊します。しかし、今回のような「境界値や例外パターンを予測して網羅する処理」を組み込めるようになったあなたなら、もうマクロの記録の枠を超えた、頼れる自動化エンジニアです。
この関数をあなたのライブラリに組み込んでおけば、CSV出力に関するトラブルとは一生無縁になれますよ。
日々の業務効率化、応援しています!
