【C#】StringBuilder.Replaceで効率的に文字列を置換する方法

目次

string.Replace とパフォーマンスの課題

C#のstring.Replaceメソッドは、文字列の一部を置換するための簡単で便利な方法です。しかし、C#のstring型は「不変(Immutable)」であるため、Replaceを実行するたびに、内部では新しい文字列オブジェクトが生成されています

string text = "A B C";
// 以下の処理は、内部的に3つの新しい文字列オブジェクトを生成する
text = text.Replace("A", "1"); // 新しい "1 B C" が生成される
text = text.Replace("B", "2"); // 新しい "1 2 C" が生成される
text = text.Replace("C", "3"); // 新しい "1 2 3" が生成される

このように置換処理が数回であれば問題ありませんが、ループ処理や複雑なテンプレート処理で何十回、何百回とReplaceを呼び出すと、不要なオブジェクトが大量に生成され、パフォーマンスの低下(特にガベージコレクションの負荷)を引き起こす原因となります。


StringBuilder.Replaceによる解決

この課題を解決するのが、System.Text.StringBuilderクラスです。StringBuilderは「可変(Mutable)」な文字列バッファであり、その中身を直接変更することができます。

StringBuilderが提供するReplaceメソッドは、新しいオブジェクトを生成せず、内部バッファの文字列を直接書き換えます。そのため、複数回の置換処理を非常に高速に実行できます。


StringBuilder.Replace の基本的な使い方

StringBuilder.Replaceは、string.Replaceと同様に、指定した文字列(oldValue)をすべて新しい文字列(newValue)に置き換えます。

  • StringBuilder.Replace(string oldValue, string newValue)

重要な特性:メソッドチェーン(連鎖)

StringBuilder.Replaceメソッドは、実行後に自分自身のインスタンス(StringBuilder)を返します

これにより、以下のようにメソッドを数珠つなぎ(メソッドチェーン)にして記述することができ、非常に効率的です。

// メソッドチェーン
sb.Replace("[TAG1]", "Value1")
  .Replace("[TAG2]", "Value2")
  .Replace("[TAG3]", "Value3");

コード例:テンプレート処理

メールテンプレートに含まれる複数のプレースホルダー([USER_NAME]など)を、StringBuilder.Replaceを使用して実際の値に効率的に置き換える例です。

using System;
using System.Text; // StringBuilder を使用するために必要

public class StringBuilderReplaceExample
{
    public static void Main()
    {
        // 1. テンプレートとなる文字列を定義
        string template = "こんにちは、[USER_NAME]様。\n" +
                          "サーバー [SERVER_ID] のメンテナンスが [DATE] に予定されています。\n" +
                          "ご注意ください。[USER_NAME]様。";

        // 2. StringBuilder を初期文字列でインスタンス化
        var sb = new StringBuilder(template);

        Console.WriteLine("--- 置換前のテンプレート ---");
        Console.WriteLine(sb.ToString()); // この時点での内容

        // 3. Replaceメソッドをチェーンして、効率的に一括置換
        // (内部バッファが直接書き換わり、新しいオブジェクトは生成されない)
        sb.Replace("[USER_NAME]", "佐藤 様")
          .Replace("[SERVER_ID]", "DB-SVR-01")
          .Replace("[DATE]", "2025年12月20日");

        // 4. 最後に ToString() で、完成した string を取得
        string completedMessage = sb.ToString();

        Console.WriteLine("\n--- 置換後のメッセージ ---");
        Console.WriteLine(completedMessage);
    }
}

出力結果:

--- 置換前のテンプレート ---
こんにちは、[USER_NAME]様。
サーバー [SERVER_ID] のメンテナンスが [DATE] に予定されています。
ご注意ください。[USER_NAME]様。

--- 置換後のメッセージ ---
こんにちは、佐藤 様様。
サーバー DB-SVR-01 のメンテナンスが 2025年12月20日 に予定されています。
ご注意ください。佐藤 様様。

(注: この例のように、元の[USER_NAME]様佐藤 様様になってしまうのはReplaceの仕様です。プレースホルダーを[USER_NAME]のみにすれば佐藤 様となります。)


使い分けの指針

string.ReplaceStringBuilder.Replaceのどちらを使うべきかは、パフォーマンスの要件によって決まります。

  • string.Replace を使う場面:
    • 置換が1回だけで終わる場合。
    • ループの外で行われる、数回程度の置換。
    • 可読性を最優先し、パフォーマンスが問題にならない場合。
  • StringBuilder.Replace を使う場面:
    • foreachforループの中でReplaceを呼び出す必要がある場合。
    • 多数の異なるプレースホルダーを持つテンプレートエンジンを実装する場合。
    • 文字列の置換処理がパフォーマンスのボトルネックになっていることが明らかな場合。

まとめ

StringBuilder.Replaceは、StringBuilderの「可変性(Mutability)」を活かした、非常に高速な文字列置換機能です。string.Replaceとは異なり、新しい文字列オブジェクトを生成せずに内部バッファを直接書き換えるため、複数回の置換(特にループ内)を行う際のパフォーマンスを劇的に改善します。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次