StringBuilderクラス

文字列の高速な結合

文字列(string型)同士の結合は+演算子やstring.Concatメソッドを使用します。
通常であればこれで十分ですが、C#ではstring型のデータは変更ができないという特徴があります。
つまり単純な文字列結合であっても新しい文字列オブジェクトを生成しているため、やや低速になります。

低速と言っても普通はまず問題にはなりませんが、同じ変数に対して何度も文字列結合を繰り返す処理がある場合はStringBuilderクラスを使用したほうが高速になる可能性があります。
StringBuilderクラスは文字列の結合時に新しいオブジェクトは生成せず、既存のオブジェクトに直接結合していきます。


string s = "a";

//時間計測のためのクラス
var sw = new System.Diagnostics.Stopwatch();

//+演算子による結合
{
    string str1 = "";

    //計測スタート
    sw.Start();

    //10万回繰り返し
    for (int i = 0; i < 100000; i++)
    {
        str1 += s;
    }

    //計測ストップ
    sw.Stop();

    //経過時間を表示
    Console.WriteLine(sw.Elapsed);
}

//経過時間をリセット
sw.Reset();

//StringBuilderによる結合
{
    StringBuilder sb = new StringBuilder();

    //計測スタート
    sw.Start();

    //10万回繰り返し
    for (int i = 0; i < 100000; i++)
    {
        sb.Append(s);
    }

    //StringBuilderをstring型に変換
    string str2 = sb.ToString();

    //計測ストップ
    sw.Stop();

    //経過時間を表示
    Console.WriteLine(sw.Elapsed);
}
00:00:00.9545671
00:00:00.0005509

実行結果は環境によって異なります。

System.Diagnostics.Stopwatchクラスは時間計測のためのクラスです。
これを利用して文字列結合に掛かった時間を計測します。
使い方はサンプルコード中のコメントを参照してください。

文字列の結合はAppendメソッドで行います。
引数はstring型以外にも組み込み型(int型やdouble型など)も指定できます。

インスタンスはそのままでは文字列として使えないので、必要な結合が終わったらToStringメソッドでstring型に変換します。

Capacityプロパティ

StringBuilderクラスは内部的に文字列を結合するためのメモリ領域をあらかじめ確保しています。
その領域のサイズを示すのがCapacityプロパティです。
型はint型です。

結合によってCapacityプロパティ以上の文字列の長さになると、自動的に新しいメモリ領域が確保されます。
Microsoftの実装では初期値が「16」で、これを超える文字数の結合が発生する度に倍々に領域が増えていくようです。
(16→32→64→128...)

CapacityプロパティはStringBuilderクラスのインスタンス生成時にあらかじめ指定することができます。
メモリの確保はそこそこコストが掛かる処理なので、どの程度の文字数になるかがあらかじめわかっているのならば最初に確保してしまった方が処理が高速になる可能性があります。


//65536文字分の領域をあらかじめ確保
StringBuilder sb = new StringBuilder(65536);

StringBuilderの内容をクリアする

StringBuilderのインスタンスの中身をクリアするには

  • Lengthプロパティに0を代入
  • Clearメソッドを使用する(.NET Framework 4.0以降)
  • 新しいインスタンスを代入する

のいずれかの方法で行います。


StringBuilder sb = new StringBuilder();
sb.Append("This is a pen.");

sb.Length = 0;

sb.Clear();

sb = new StringBuilder();

どの方法でも大した差はないので好みの問題です。
しかし前二つの方法ではCapacityプロパティはそのままですのでメモリ領域は確保されたままになることに注意が必要です。
必要に応じてCapacityプロパティもセットしておきます。


StringBuilder sb = new StringBuilder();
sb.Append("This is a pen.");

sb.Length = 0;
sb.Capacity = 16;

新しいインスタンスを代入する場合はCapacityプロパティも既定値にセットされます。

Insert、Remove、Replace

StringBuilderクラスは文字列を整形することもできます。

Insertメソッドは指定の場所に文字列を挿入します。
Removeメソッドは指定の場所から指定の長さの文字列を削除します。
Replaceメソッドは指定の文字列を別の文字列に置き換えます。


StringBuilder sb = new StringBuilder();
sb.Append("This is a pen.");

//10文字目に文字列を挿入
sb.Insert(10, "red ");
Console.WriteLine(sb.ToString());

//10文字目から4文字削除
sb.Remove(10, 4);
Console.WriteLine(sb.ToString());

//"a pen"を"an apple"に置き換え
sb.Replace("a pen", "an apple");
Console.WriteLine(sb.ToString());
This is a red pen.
This is a pen.
This is an apple.

ただ、単純な文字列操作の目的でStringBuilderクラスは使用すべきではありません。
StringBuilderクラスはインスタンスの生成およびstring型への変換処理があるため、その点はstring型に比べて余計なコストがかかります。
StringBuilderは同一オブジェクトに対してループ文などで何十何百と文字列操作を行う場合に有効なクラスです。