🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の文字列結合 — & と + の違い、そして文字列を壊す Null の罠

|

Excel VBA の文字列結合 — & と + の違い、そして文字列を壊す Null の罠

TL;DR — VBA には、どちらもテキストを結合するように見える演算子が 2 つあります。&+ です。安全なのは片方だけ。& は常に両辺をテキスト として扱い、数値はその桁の文字に変換し、Null は空文字列として扱います。 一方 + は数値を見ると算術演算をし、Null を見ると伝染します(1 つの Null が結果全体を Null にしてしまう)。例外のないルール:文字列を組み立てる なら &、計算には +。そして、ループの中で何千もの断片をつなぐときは s = s & x をやめましょう — これは O(n²) です。代わりに配列に対して Join を使います。

文字列結合は、VBA でテキストを扱うときに最もよく行う操作です。ファイル名、 メッセージ、SQL 文、レポートのタイトルを組み立てる、といった具合に。一見ささいな 操作ですが、数値や空白セルが紛れ込んだ瞬間に "Total: " + value が間違った数値か 無言の Null に化け、何のエラーも出ないまま、そのバグが本番に紛れ込みます。

この記事で学べること

  • なぜ & だけが信頼できる結合演算子なのか(そして + が実際に何をしているのか)
  • 式全体をゼロにしてしまう +Null の罠
  • ループ内の s = s & item がなぜ密かに O(n²) なのか — そして Join による解決
  • & が型宣言文字と誤解されるバグを防ぐ「空白を入れる」習慣

考え方の軸:& は接着剤、+ はあなたを裏切る「偽の接着剤」

& を、**「テキスト専用」**と書かれた接着剤のチューブだと考えてください。 渡されたものが何であれ — 文字列、数値、日付、空白でさえ — テキストに変換して 末尾にくっつけます。+ は見た目がまったく同じチューブですが、ラベルには **「まず算術」**と書かれています。両辺がたまたま文字列のときは結合します。 しかし片方が数値か Null になった瞬間、接着剤であることをやめて算術演算を始める のです — そして出力が間違うまで、あなたはそれに気づきません。

Sub TwoOperators()
    ' & は常にテキストとして結合する
    Debug.Print "Item " & 5          ' -> "Item 5"   (数値がテキストに変換される)
    Debug.Print "5" & "5"            ' -> "55"        (結合される)

    ' + は数値が絡んだ瞬間に算術演算をする
    Debug.Print "5" + "5"            ' -> "55"  ... ただし両辺がテキストだから成り立つだけ
    Debug.Print 5 + 5               ' -> 10    (算術演算)
    Debug.Print "Item " + 5         ' -> run-time error 13: 型が一致しません
End Sub

最後の行が決定的な証拠です。"Item " + 5 がエラーになるのは、+ が数値を文字列に 足そうとするからです。& にはこの問題が一切ありません — "Item " & 5 はそのまま 動きます。

最悪の結合バグを防ぐルール:Null の罠

ここからが、実際にデータを破壊する失敗パターンです。データベースのレコードセット、 空の Variant、Null として返ってきたセルから値を読むとき、2 つの演算子は 正反対の振る舞いをします。

Sub TheNullTrap()
    Dim middleName As Variant
    middleName = Null                       ' 例:ADO から返ってきた空のフィールド

    ' & は Null を空文字列として扱う — 安全
    Debug.Print "Anna " & middleName & " Smith"   ' -> "Anna  Smith"

    ' + は伝染する:たった 1 つの Null が式全体を汚染する
    Debug.Print "Anna " + middleName + " Smith"   ' -> Null  (すべて消える)
End Sub

+ を使うと、チェーンのどこか 1 か所にある Null が結果全体Null に してしまいます。それをそのままセルに書き込めば、名前が入るはずの場所が空白になり — しかも理由を教えてくれるエラーは出ません。「結合した結果がランダムに空セルになる」 というバグ報告が存在する一番の理由がこれです。解決策は、すべての値を Null か どうかチェックすることではありません。解決策は、文字列の組み立てに + を 絶対に使わないことです。+ は、Null の伝播を意図的にシグナルとして利用したい ケースのためにとっておきます — 実務上、そんなケースはほぼありません。

空白を入れる習慣:& は型宣言文字でもある

コードを詰めて書く人を悩ませる、微妙な落とし穴です。VBA では、変数名の後ろに 付けた &Long 型を表す古い型宣言の接尾辞です(String に対する $ と同じ)。 そのため & を空白なしで名前にくっつけると、パーサーがそれを結合演算子ではなく 型文字として読んでしまうことがあります。

    total = count&"x"      ' あいまい — VBE は count& を Long と誤読する可能性がある
    total = count & "x"    ' 明確 — 常に結合になる

& の前後には必ず空白を入れましょう。これは見た目の問題ではありません。現実の 構文上のあいまいさを取り除き、長い結合を読みやすくします。断片の間には Chr(10) をベタ書きするのではなく、vbNewLinevbCrLfvbTab といった定数を 使いましょう。

    msg = "Line one" & vbNewLine & "Line two" & vbTab & "(indented)"

結合が遅い理由:O(n²) のループ

これは、まばたきする間に終わるマクロと、30 秒間フリーズするマクロとを分ける パフォーマンス上の判断です。VBA の文字列はイミュータブル(変更不可)で、 s = s & item のたびにまったく新しい文字列を確保し、それまでの内容をすべて コピーします。これをループで 10,000 回繰り返せば、伸び続ける文字列を 10,000 回 コピーしたことになります — 典型的な O(n²) です。

' 遅い — 毎回文字列全体を再構築する (O(n²))
Dim s As String, i As Long
For i = 1 To 10000
    s = s & data(i) & ","
Next i

' 速い — 配列に集めて、Join で一度に結合する (O(n))
Dim parts() As String
ReDim parts(1 To 10000)
For i = 1 To 10000
    parts(i) = data(i)
Next i
s = Join(parts, ",")          ' メモリ確保は一度だけ

JoinSplit の逆操作です。配列と区切り文字を受け取り、 一度のメモリ確保で 1 つの文字列を返します。数百回を超える繰り返しなら、配列を 組み立てて Join を一度呼ぶ方が、& で積み上げるよりも圧倒的に速く — しかも 読みやすくなります。

判断の目安:ほんの数個の断片なら & で十分で、Join はやり過ぎです。大きな 文字列を組み立てるループなら、毎回 Join に手を伸ばしましょう。

セル範囲を結合する

非常によくある要望が、セルが並んだ列を 1 つの区切り文字列に結合することです。 避けられるなら、セルを 1 つずつループするのはやめましょう — Excel 自身の TEXTJOINWorksheetFunction 経由で使えます)が、一度の呼び出しでそれをこなし、 空白も飛ばしてくれます。

Sub JoinAColumn()
    Dim result As String
    ' TEXTJOIN(区切り文字, 空白を無視, 範囲)
    result = WorksheetFunction.TextJoin(", ", True, Range("A1:A50"))
    Debug.Print result
End Sub

どうしても VBA のループが必要なら(TEXTJOIN のない古い Excel など)、まず範囲を Variant 配列に読み込み、String 配列を組み立てて Join します — ループの中で ワークシートに 50 回もアクセスしてはいけません。

ExcelMaster の活用

結合系の VBA の多くは、結局 1 つのものを組み立てるために存在します。きれいな エクスポート — CSV の 1 行、整形済みのラベル、突き合わせ用のキーです。 ExcelMaster は、こうしたものを平易な日本語の説明から組み立てます。 「顧客 ID と注文日を組み合わせてキー列を作って、カンマ区切りで」といった具合に。 しかも &+ の違いや Null の伝播を考えなくても、空白も型も区切り文字も 処理してくれます。

常駐マクロの中に結合処理が組み込まれている場合は、これからも VBA を書くことに なるでしょう。しかし「これらの列をつないでエクスポートする」という単発の作業なら、 出力を言葉で説明する方が、演算子を手作業で正しく書くより速いのです。

よくある質問

VBA の & と + の違いは何ですか?

& は常にテキストとして結合します — 数値はその桁の文字に変換し、Null は空文字列 として扱います。+ は数値が絡むと算術演算をし、Null を伝播させます(1 つの Null が式全体を Null にします)。文字列の組み立てには & を、計算だけに + を 使いましょう。

結合した文字列に改行を入れるにはどうすればいいですか?

断片の間に vbNewLine 定数(または vbCrLf)を挟みます。 "Line 1" & vbNewLine & "Line 2" のように。タブには vbTab を使います。これらは Chr(13)Chr(10) をベタ書きするより読みやすく、移植性も高くなります。

VBA の文字列結合がとても遅いのはなぜですか?

ほぼ間違いなく、大きなループの中で s = s & x で積み上げているからです。VBA は 毎回文字列全体を再構築するため、これは O(n²) になります。断片を String 配列に 集めて、Join(parts, delimiter) を一度だけ呼びましょう。

VBA でセル範囲を結合するにはどうすればいいですか?

WorksheetFunction.TextJoin(区切り文字, 空白を無視, 範囲) を使えば、空白も飛ばして くれる 1 行の解決策になります。ループに頼るのは TEXTJOIN のない古い Excel の 場合だけにしましょう。その場合でも、セルを 1 つずつループするのではなく、範囲を 配列に読み込んでから Join します。

検証環境

検証環境: Excel 365(Windows 11)、VBA 7.1 — 最終確認 2026-06-14。

関連ガイド: VBA UCase & LCase · VBA Str · VBA Split · VBA CStr · VBA For Loop