文字列結合
複数の文字列を連結して 1 つの文字列にする処理。+ 演算子やテンプレートリテラルなどで実現する。
文字列結合 (String Concatenation) とは、複数の文字列を連結して 1 つの文字列を生成する処理です。ほぼすべてのプログラミング言語で基本操作として提供されており、ユーザーインターフェースの構築、ログメッセージの生成、SQL クエリの組み立てなど、あらゆる場面で使用されます。単純な操作に見えますが、大量のデータを扱う場面では言語や実装によって性能特性が大きく異なるため、それぞれの前提を理解しておくことが重要です。
JavaScript では + 演算子、concat() メソッド、テンプレートリテラル (`${}`) の 3 つの方法で文字列を結合できます。ループ内で += を繰り返すと新しい文字列オブジェクトが毎回生成されて処理時間が O(n²) に近づく、という説明が広く流布していますが、2026 年時点の V8 (Chrome・Node.js) には当てはまりません。V8 は結合結果をすぐに 1 本の文字列へ平坦化せず、2 つの文字列を指す連結ノードとして保持し、実際に内容を読み出す時点で初めて平坦化します。このため 100 万回の += でも配列の join('') とほぼ同じ時間で終わります。join() を選ぶ理由は速度ではなく、区切り文字を一箇所で指定できることと、途中の要素を配列のまま検査・加工できることにあります。なお [...items].join('') のようにスプレッドを挟むと配列を丸ごと複製する分だけ無駄が増えるため、すでに配列であれば items.join('') と書きます。
Python では + 演算子のほか、f-string や ''.join() が使われます。公式ドキュメントの Programming FAQ は、文字列は不変であるため多数の連結は一般に総文字列長に対して二次のコストになると説明し、リストに溜めてから最後に ''.join() で一度に連結する書き方を推奨しています。ただし CPython には、連結先の変数がその文字列への唯一の参照を持つ場合に限り、新しいオブジェクトを作らず領域を伸ばす実装依存の最適化があります。効くかどうかは書き方ひとつで変わり、同じ 20 万回のループでも途中結果を別の変数にも持たせただけで数十倍から数百倍の時間がかかります (Python 3.13 の実測で 1 文字追記なら約 50 倍・10 文字追記なら約 370 倍)。最適化が効く条件を見極めるより、リストに溜めて join() する形を既定にするほうが安全です。Java では StringBuilder クラスが可変長の文字列バッファを提供し、ループ内での結合に適しています。Go 言語では strings.Builder が同様の役割を果たします。
文字列結合と混同されやすい概念に文字列補間 (String Interpolation) があります。文字列結合は複数の文字列を物理的に連結する操作であるのに対し、文字列補間はテンプレート内に変数や式の値を埋め込む構文です。JavaScript のテンプレートリテラル `Hello, ${name}!` は文字列補間の一種であり、内部的には文字列結合が行われますが、可読性の面で優れています。
文字エンコーディングの扱いにも注意が必要です。文字列型が Unicode で統一されている言語 (Java・JavaScript・Python 3 など) では、結合そのものが文字化けを引き起こすことはありません。化けるのはその前段、バイト列を文字列へ変換する境界で誤ったエンコーディングを指定した時点です。データベースから取得した値やファイルから読み込んだテキストが崩れている場合、疑うべきは結合処理ではなく接続時の文字セット指定や読み込み時のエンコーディング指定です。UTF-8 と Shift_JIS が混在する環境では、まず境界での指定を揃えてから結合します。また、ユーザー入力をそのまま結合して SQL クエリや HTML を生成すると、SQL インジェクションや XSS の脆弱性につながるため、パラメータ化クエリやエスケープ処理を必ず併用しましょう。
文字数カウントの観点では、結合後の文字数が結合元の合計と一致するかどうかは、数える単位によって変わります。コードポイント単位なら合計と一致し、セパレータ (区切り文字) を挿入した分だけ加算されます。たとえば 3 つの単語をカンマ区切りで結合すると、セパレータ 2 つ分の文字数が追加されます。一方、表示上の 1 文字にあたる書記素クラスタ単位では合計が成り立ちません。「か」と結合文字の濁点をつなぐと合わせて 1 文字の「が」になり、地域表示符号を 2 つつなぐと 1 つの国旗になり、人物の絵文字と ZWJ (ゼロ幅接合子) で始まる列をつなぐと 1 つの家族絵文字になります。いずれも 1 + 1 や 1 + 2 の結果が 1 になる例です。境界をまたいで結合が起きるのは、断片化した入力を継ぎ足す場面や、分割送信されたテキストを組み立てる場面です。入力欄の残り文字数のように表示上の文字数を扱う場合は、結合前の値を足し合わせるのではなく、結合後の最終的な文字列に対して数え直すのが確実です。