System.Text.StringBuilder-Klasse

Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.

Die StringBuilder Klasse stellt ein zeichenfolgenähnliches Objekt dar, dessen Wert eine veränderbare Abfolge von Zeichen ist.

StringBuilder im Vergleich zum Zeichenfolgentyp

Obwohl StringBuilder und String beide Sequenzen von Zeichen darstellen, werden sie unterschiedlich implementiert. String ist ein unveränderlicher Typ. Das heißt, jeder Vorgang, der scheinbar ein String Objekt ändert, erstellt tatsächlich eine neue Zeichenfolge.

Beispielsweise wird der Aufruf der String.Concat Methode im folgenden C#-Beispiel angezeigt, um den Wert einer Zeichenfolgenvariable namens valuezu ändern. Tatsächlich gibt die Concat Methode ein value Objekt zurück, das einen anderen Wert und eine andere Adresse aufweist als das value Objekt, das an die Methode übergeben wurde. Beachten Sie, dass das Beispiel mithilfe der /unsafe Compileroption kompiliert werden muss.

using System;

public class Example7
{
    public unsafe static void Main()
    {
        string value = "This is the first sentence" + ".";
        fixed (char* start = value)
        {
            value = String.Concat(value, "This is the second sentence. ");
            fixed (char* current = value)
            {
                Console.WriteLine(start == current);
            }
        }
    }
}
// The example displays the following output:
//      False
    let mutable value = "This is the first sentence" + "."
    use start = fixed value
    value <- System.String.Concat(value, "This is the second sentence. ")
    use current = fixed value
    printfn $"{start = current}"
// The example displays the following output:
//      False

Bei Routinen, die umfangreiche Zeichenfolgenmanipulation durchführen (z. B. Apps, die eine Zeichenfolge mehrmals in einer Schleife ändern), kann das Ändern einer Zeichenfolge wiederholt eine erhebliche Leistungseinbuße bedeuten. Die Alternative besteht darin, eine veränderbare Zeichenfolgenklasse zu verwenden StringBuilder. Die Veränderbarkeit bedeutet, dass sie nach der Erstellung einer Instanz der Klasse geändert werden kann, indem Sie Zeichen anfügen, entfernen, ersetzen oder einfügen. Ein StringBuilder Objekt Standard enthält einen Puffer, um Erweiterungen in die Zeichenfolge aufzunehmen. Neue Daten werden an den Puffer angefügt, wenn Raum verfügbar ist; andernfalls wird ein neuer, größerer Puffer zugewiesen, Daten aus dem ursprünglichen Puffer in den neuen Puffer kopiert, und die neuen Daten werden dann an den neuen Puffer angefügt.

Wichtig

Obwohl die StringBuilder Klasse im Allgemeinen eine bessere Leistung als die String Klasse bietet, sollten Sie nicht automatisch durch StringBuilder jedes Mal ersetzenString, wenn Sie Zeichenfolgen bearbeiten möchten. Die Leistung hängt von der Größe der Zeichenfolge, der Menge des Speichers ab, der für die neue Zeichenfolge zugewiesen werden soll, dem System, auf dem Der Code ausgeführt wird, und dem Typ des Vorgangs. Sie sollten bereit sein, Ihren Code zu testen, um festzustellen, ob StringBuilder tatsächlich eine erhebliche Leistungsverbesserung bietet.

Erwägen Sie die Verwendung der String Klasse unter diesen Bedingungen:

  • Wenn die Anzahl der Änderungen, die Ihr Code an einer Zeichenfolge vorgibt, klein ist. In diesen Fällen StringBuilder kann es vernachlässigbar oder gar keine Leistungsverbesserung Stringbieten.

  • Wenn Sie eine feste Anzahl von Verkettungsvorgängen ausführen, insbesondere bei Zeichenfolgenliteralen. In diesem Fall kann der Compiler die Verkettungsvorgänge in einem einzigen Vorgang kombinieren.

  • Wenn Sie umfangreiche Suchvorgänge ausführen müssen, während Sie ihre Zeichenfolge erstellen. Die StringBuilder Klasse verfügt nicht über Suchmethoden wie IndexOf z. B. oder StartsWith. Sie müssen das StringBuilder Objekt für diese Vorgänge in ein String Objekt konvertieren, und dies kann den Leistungsvorteil von der Verwendung StringBuilderverengnen. Weitere Informationen finden Sie im Abschnitt "Durchsuchen des Texts in einem StringBuilder-Objekt ".

Erwägen Sie die Verwendung der StringBuilder Klasse unter diesen Bedingungen:

  • Wenn Sie erwarten, dass ihr Code zur Entwurfszeit eine unbekannte Anzahl von Änderungen an einer Zeichenfolge vorgibt (z. B. wenn Sie eine Schleife verwenden, um eine zufällige Anzahl von Zeichenfolgen zu verketten, die Benutzereingaben enthalten).
  • Wenn Sie erwarten, dass Ihr Code eine erhebliche Anzahl von Änderungen an einer Zeichenfolge vorgibt.

Funktionsweise von StringBuilder

Die StringBuilder.Length Eigenschaft gibt die Anzahl der Zeichen an, die das StringBuilder Objekt derzeit enthält. Wenn Sie dem StringBuilder Objekt Zeichen hinzufügen, nimmt die Länge zu, bis sie der Größe der StringBuilder.Capacity Eigenschaft entspricht, wodurch die Anzahl der Zeichen definiert wird, die das Objekt enthalten kann. Wenn die Anzahl der hinzugefügten Zeichen dazu führt, dass die Länge des StringBuilder Objekts seine aktuelle Kapazität überschreitet, wird neuer Speicher zugewiesen, der Wert der Capacity Eigenschaft wird verdoppelt, dem Objekt neue Zeichen hinzugefügt StringBuilder , und seine Length Eigenschaft wird angepasst. Zusätzlicher Arbeitsspeicher für das StringBuilder Objekt wird dynamisch zugewiesen, bis er den von der StringBuilder.MaxCapacity Eigenschaft definierten Wert erreicht. Wenn die maximale Kapazität erreicht ist, kann dem Objekt kein weiterer Arbeitsspeicher zugewiesen StringBuilder werden, und der Versuch, Zeichen hinzuzufügen oder über die maximale Kapazität hinaus zu erweitern, löst entweder eine ArgumentOutOfRangeException oder eine Ausnahme aus OutOfMemoryException .

Im folgenden Beispiel wird veranschaulicht, wie ein StringBuilder Objekt neuen Arbeitsspeicher zuweist und seine Kapazität dynamisch erhöht, wenn die dem Objekt zugewiesene Zeichenfolge erweitert wird. Der Code erstellt ein StringBuilder Objekt durch Aufrufen des Standardkonstruktors (parameterlos). Die Standardkapazität dieses Objekts beträgt 16 Zeichen, und die maximale Kapazität beträgt mehr als 2 Milliarden Zeichen. Das Anfügen der Zeichenfolge "Dies ist ein Satz". Führt zu einer neuen Speicherzuweisung, da die Zeichenfolgenlänge (19 Zeichen) die Standardkapazität des StringBuilder Objekts überschreitet. Die Kapazität des Objekts verdoppelt sich auf 32 Zeichen, die neue Zeichenfolge wird hinzugefügt, und die Länge des Objekts entspricht jetzt 19 Zeichen. Der Code fügt dann die Zeichenfolge "Dies ist ein zusätzlicher Satz" an den Wert des StringBuilder Objekts 11 Mal an. Wenn der Anfügevorgang bewirkt, dass die Länge des StringBuilder Objekts seine Kapazität überschreitet, wird die vorhandene Kapazität verdoppelt und der Append Vorgang erfolgreich ausgeführt.

using System;
using System.Reflection;
using System.Text;

public class Example4
{
    public static void Main()
    {
        StringBuilder sb = new StringBuilder();
        ShowSBInfo(sb);
        sb.Append("This is a sentence.");
        ShowSBInfo(sb);
        for (int ctr = 0; ctr <= 10; ctr++)
        {
            sb.Append("This is an additional sentence.");
            ShowSBInfo(sb);
        }
    }

    private static void ShowSBInfo(StringBuilder sb)
    {
        foreach (var prop in sb.GetType().GetProperties())
        {
            if (prop.GetIndexParameters().Length == 0)
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb));
        }
        Console.WriteLine();
    }
}
// The example displays the following output:
//    Capacity: 16    MaxCapacity: 2,147,483,647    Length: 0
//    Capacity: 32    MaxCapacity: 2,147,483,647    Length: 19
//    Capacity: 64    MaxCapacity: 2,147,483,647    Length: 50
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 81
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 112
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 143
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 174
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 205
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 236
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 267
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 298
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 329
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 360
open System.Text

let showSBInfo (sb: StringBuilder) =
    for prop in sb.GetType().GetProperties() do
        if prop.GetIndexParameters().Length = 0 then
            printf $"{prop.Name}: {prop.GetValue sb:N0}    "

    printfn ""

let sb = StringBuilder()
showSBInfo sb
sb.Append "This is a sentence." |> ignore
showSBInfo sb

for i = 0 to 10 do
    sb.Append "This is an additional sentence." |> ignore
    showSBInfo sb

// The example displays the following output:
//    Capacity: 16    MaxCapacity: 2,147,483,647    Length: 0
//    Capacity: 32    MaxCapacity: 2,147,483,647    Length: 19
//    Capacity: 64    MaxCapacity: 2,147,483,647    Length: 50
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 81
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 112
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 143
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 174
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 205
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 236
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 267
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 298
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 329
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 360
Imports System.Reflection
Imports System.Text

Module Example5
    Public Sub Main()
        Dim sb As New StringBuilder()
        ShowSBInfo(sb)
        sb.Append("This is a sentence.")
        ShowSBInfo(sb)
        For ctr As Integer = 0 To 10
            sb.Append("This is an additional sentence.")
            ShowSBInfo(sb)
        Next
    End Sub

    Public Sub ShowSBInfo(sb As StringBuilder)
        For Each prop In sb.GetType().GetProperties
            If prop.GetIndexParameters().Length = 0 Then
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb))
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' The example displays the following output:
'    Capacity: 16    MaxCapacity: 2,147,483,647    Length: 0
'    Capacity: 32    MaxCapacity: 2,147,483,647    Length: 19
'    Capacity: 64    MaxCapacity: 2,147,483,647    Length: 50
'    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 81
'    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 112
'    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 143
'    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 174
'    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 205
'    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 236
'    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 267
'    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 298
'    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 329
'    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 360

Arbeitsspeicherbelegung

Die Standardkapazität eines StringBuilder Objekts beträgt 16 Zeichen, und die maximale Standardkapazität ist Int32.MaxValue. Diese Standardwerte werden verwendet, wenn Sie die StringBuilder() Konstruktoren aufrufen StringBuilder(String) .

Sie können die Anfangskapazität eines StringBuilder Objekts auf folgende Weise explizit definieren:

  • Durch Aufrufen eines der Konstruktoren, die StringBuilder einen capacity Parameter enthalten, wenn Sie das Objekt erstellen.

  • Indem Sie der StringBuilder.Capacity Eigenschaft explizit einen neuen Wert zuweisen, um ein vorhandenes StringBuilder Objekt zu erweitern. Beachten Sie, dass die Eigenschaft eine Ausnahme auslöst, wenn die neue Kapazität kleiner als die vorhandene Kapazität oder größer als die maximale Kapazität des StringBuilder Objekts ist.

  • Durch Aufrufen der StringBuilder.EnsureCapacity Methode mit der neuen Kapazität. Die neue Kapazität darf nicht größer als die maximale Kapazität des StringBuilder Objekts sein. Im Gegensatz zu einer Zuordnung zur Capacity Eigenschaft wird jedoch keine Ausnahme ausgelöst, EnsureCapacity wenn die gewünschte neue Kapazität kleiner als die vorhandene Kapazität ist. In diesem Fall hat der Methodenaufruf keine Auswirkung.

Wenn die Länge der dem StringBuilder Objekt im Konstruktoraufruf zugewiesenen Zeichenfolge entweder die Standardkapazität oder die angegebene Kapazität überschreitet, wird die Capacity Eigenschaft auf die Länge der mit dem value Parameter angegebenen Zeichenfolge festgelegt.

Sie können die maximale Kapazität eines StringBuilder Objekts explizit definieren, indem Sie den StringBuilder(Int32, Int32) Konstruktor aufrufen. Sie können die maximale Kapazität nicht ändern, indem Sie der MaxCapacity Eigenschaft einen neuen Wert zuweisen, da sie schreibgeschützt ist.

Wie im vorherigen Abschnitt gezeigt wird, wird bei unzureichender Kapazität zusätzlicher Arbeitsspeicher zugewiesen, und die Kapazität eines StringBuilder Objekts verdoppelt sich auf den von der MaxCapacity Eigenschaft definierten Wert.

Im Allgemeinen sind die Standardkapazität und die maximale Kapazität für die meisten Apps ausreichend. Sie können diese Werte unter den folgenden Bedingungen festlegen:

  • Wenn die letztendliche Größe des StringBuilder Objekts wahrscheinlich größer als sehr groß wird, in der Regel über mehrere Megabyte. In diesem Fall kann es zu leistungseinbußen kommen, wenn die anfängliche Capacity Eigenschaft auf einen erheblich hohen Wert festgelegt wird, um die Notwendigkeit zu vieler Speicherverlagerungen zu vermeiden.

  • Wenn Ihr Code auf einem System mit eingeschränktem Arbeitsspeicher ausgeführt wird. In diesem Fall empfiehlt es sich, die MaxCapacity Eigenschaft auf weniger festzulegen, als Int32.MaxValue wenn ihr Code große Zeichenfolgen verarbeitet, die dazu führen können, dass sie in einer speichergeschränkten Umgebung ausgeführt wird.

Instanziieren eines StringBuilder-Objekts

Sie instanziieren ein StringBuilder Objekt, indem Sie einen der sechs überladenen Klassenkonstruktoren aufrufen, die in der folgenden Tabelle aufgeführt sind. Drei der Konstruktoren instanziieren ein StringBuilder Objekt, dessen Wert eine leere Zeichenfolge ist, aber seine Capacity werte MaxCapacity unterschiedlich festlegen. Die neu Standard drei Konstruktoren definieren ein StringBuilder Objekt mit einem bestimmten Zeichenfolgenwert und einer bestimmten Kapazität. Zwei der drei Konstruktoren verwenden die standardmäßige maximale Kapazität von Int32.MaxValue, während der dritte die maximale Kapazität festlegen kann.

Konstruktor Zeichenfolgenwert Capacity Maximale Kapazität
StringBuilder() String.Empty 16 Int32.MaxValue
StringBuilder(Int32) String.Empty Definiert durch den capacity Parameter Int32.MaxValue
StringBuilder(Int32, Int32) String.Empty Definiert durch den capacity Parameter Definiert durch den maxCapacity Parameter
StringBuilder(String) Definiert durch den value Parameter 16 oder value. Length, je nachdem, was größer ist Int32.MaxValue
StringBuilder(String, Int32) Definiert durch den value Parameter Definiert durch den capacity Parameter oder value. Length, je nachdem, was größer ist. Int32.MaxValue
StringBuilder(String, Int32, Int32, Int32) wird von value definiert Substring(startIndex, length) Definiert durch den capacity Parameter oder value. Length, je nachdem, was größer ist. Int32.MaxValue

Im folgenden Beispiel werden drei dieser Konstruktorüberladungen zum Instanziieren StringBuilder von Objekten verwendet.

using System;
using System.Text;

public class Example8
{
    public static void Main()
    {
        string value = "An ordinary string";
        int index = value.IndexOf("An ") + 3;
        int capacity = 0xFFFF;

        // Instantiate a StringBuilder from a string.
        StringBuilder sb1 = new StringBuilder(value);
        ShowSBInfo(sb1);

        // Instantiate a StringBuilder from string and define a capacity.  
        StringBuilder sb2 = new StringBuilder(value, capacity);
        ShowSBInfo(sb2);

        // Instantiate a StringBuilder from substring and define a capacity.  
        StringBuilder sb3 = new StringBuilder(value, index,
                                              value.Length - index,
                                              capacity);
        ShowSBInfo(sb3);
    }

    public static void ShowSBInfo(StringBuilder sb)
    {
        Console.WriteLine("\nValue: {0}", sb.ToString());
        foreach (var prop in sb.GetType().GetProperties())
        {
            if (prop.GetIndexParameters().Length == 0)
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb));
        }
        Console.WriteLine();
    }
}
// The example displays the following output:
//    Value: An ordinary string
//    Capacity: 18    MaxCapacity: 2,147,483,647    Length: 18
//    
//    Value: An ordinary string
//    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 18
//    
//    Value: ordinary string
//    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 15
open System.Text

let showSBInfo (sb: StringBuilder) =
    for prop in sb.GetType().GetProperties() do
        if prop.GetIndexParameters().Length = 0 then
            printf $"{prop.Name}: {prop.GetValue sb:N0}    "

    printfn ""

let value = "An ordinary string"
let index = value.IndexOf "An " + 3
let capacity = 0xFFFF

// Instantiate a StringBuilder from a string.
let sb1 = StringBuilder value
showSBInfo sb1

// Instantiate a StringBuilder from string and define a capacity.
let sb2 = StringBuilder(value, capacity)
showSBInfo sb2

// Instantiate a StringBuilder from substring and define a capacity.
let sb3 = StringBuilder(value, index, value.Length - index, capacity)
showSBInfo sb3

// The example displays the following output:
//    Value: An ordinary string
//    Capacity: 18    MaxCapacity: 2,147,483,647    Length: 18
//
//    Value: An ordinary string
//    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 18
//
//    Value: ordinary string
//    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 15
Imports System.Text

Module Example8
    Public Sub Main()
        Dim value As String = "An ordinary string"
        Dim index As Integer = value.IndexOf("An ") + 3
        Dim capacity As Integer = &HFFFF

        ' Instantiate a StringBuilder from a string.
        Dim sb1 As New StringBuilder(value)
        ShowSBInfo(sb1)

        ' Instantiate a StringBuilder from string and define a capacity.  
        Dim sb2 As New StringBuilder(value, capacity)
        ShowSBInfo(sb2)

        ' Instantiate a StringBuilder from substring and define a capacity.  
        Dim sb3 As New StringBuilder(value, index,
                                   value.Length - index,
                                   capacity)
        ShowSBInfo(sb3)
    End Sub

    Public Sub ShowSBInfo(sb As StringBuilder)
        Console.WriteLine()
        Console.WriteLine("Value: {0}", sb.ToString())
        For Each prop In sb.GetType().GetProperties
            If prop.GetIndexParameters().Length = 0 Then
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb))
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' The example displays the following output:
'    Value: An ordinary string
'    Capacity: 18    MaxCapacity: 2,147,483,647    Length: 18
'    
'    Value: An ordinary string
'    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 18
'    
'    Value: ordinary string
'    Capacity: 65,535    MaxCapacity: 2,147,483,647    Length: 15

Aufrufen von StringBuilder-Methoden

Die meisten Methoden, die die Zeichenfolge in einer StringBuilder Instanz ändern, geben einen Verweis auf dieselbe Instanz zurück. Auf diese Weise können Sie Methoden auf zwei Arten aufrufen StringBuilder :

  • Sie können einzelne Methodenaufrufe ausführen und den Rückgabewert ignorieren, wie im folgenden Beispiel gezeigt.

    using System;
    using System.Text;
    
    public class Example
    {
       public static void Main()
       {
          StringBuilder sb = new StringBuilder();
          sb.Append("This is the beginning of a sentence, ");
          sb.Replace("the beginning of ", "");
          sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ");
          sb.Replace(",", ".");
          Console.WriteLine(sb.ToString());
       }
    }
    // The example displays the following output:
    //        This is a complete sentence.
    
    open System.Text
    
    let sb = StringBuilder()
    sb.Append "This is the beginning of a sentence, " |> ignore
    sb.Replace("the beginning of ", "") |> ignore
    sb.Insert((string sb).IndexOf "a " + 2, "complete ") |> ignore
    sb.Replace(",", ".") |> ignore
    printfn $"{sb}"
    // The example displays the following output:
    //        This is a complete sentence.
    
    Imports System.Text
    
    Module Example2
        Public Sub Main()
            Dim sb As New StringBuilder()
            sb.Append("This is the beginning of a sentence, ")
            sb.Replace("the beginning of ", "")
            sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ")
            sb.Replace(",", ".")
            Console.WriteLine(sb.ToString())
        End Sub
    End Module
    ' The example displays the following output:
    '       This is a complete sentence.
    
  • Sie können eine Reihe von Methodenaufrufen in einer einzelnen Anweisung ausführen. Dies kann praktisch sein, wenn Sie eine einzelne Anweisung schreiben möchten, die aufeinander folgende Vorgänge verkettet. Im folgenden Beispiel werden drei Methodenaufrufe aus dem vorherigen Beispiel in einer einzigen Codezeile konsolidiert.

    using System;
    using System.Text;
    
    public class Example2
    {
        public static void Main()
        {
            StringBuilder sb = new StringBuilder("This is the beginning of a sentence, ");
            sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2,
                                                       "complete ").Replace(",", ".");
            Console.WriteLine(sb.ToString());
        }
    }
    // The example displays the following output:
    //        This is a complete sentence.
    
    open System.Text
    
    let sb = StringBuilder "This is the beginning of a sentence, "
    
    sb
        .Replace("the beginning of ", "")
        .Insert((string sb).IndexOf "a " + 2, "complete ")
        .Replace(",", ".")
    |> ignore
    
    printfn $"{sb}"
    // The example displays the following output:
    //        This is a complete sentence.
    
    Imports System.Text
    
    Module Example3
        Public Sub Main()
            Dim sb As New StringBuilder("This is the beginning of a sentence, ")
            sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2,
                                                     "complete ").Replace(", ", ".")
            Console.WriteLine(sb.ToString())
        End Sub
    End Module
    ' The example displays the following output:
    '       This is a complete sentence.
    

Ausführen von StringBuilder-Vorgängen

Sie können die Methoden der StringBuilder Klasse verwenden, um Zeichen in einem StringBuilder Objekt zu durchlaufen, hinzuzufügen, zu löschen oder zu ändern.

Durchlaufen von StringBuilder-Zeichen

Sie können mithilfe der StringBuilder.Chars[] Eigenschaft auf die Zeichen in einem StringBuilder Objekt zugreifen. In C# Chars[] ist ein Indexer; in Visual Basic ist es die Standardeigenschaft der StringBuilder Klasse. Auf diese Weise können Sie einzelne Zeichen nur mithilfe ihres Indexes festlegen oder abrufen, ohne explizit auf die Chars[] Eigenschaft zu verweisen. Zeichen in einem StringBuilder Objekt beginnen bei Index 0 (Null) und fahren mit index Length - 1 fort.

Das folgende Beispiel veranschaulicht die Chars[] Eigenschaft. Es fügt zehn Zufallszahlen an ein StringBuilder Objekt an und durchläuft dann jedes Zeichen. Wenn die Unicode-Kategorie des Zeichens lautet UnicodeCategory.DecimalDigitNumber, wird die Zahl um 1 verringert (oder die Zahl wird in 9 geändert, wenn der Wert 0 ist). Im Beispiel wird der Inhalt des StringBuilder Objekts sowohl vor als auch nach dem Ändern der Werte einzelner Zeichen angezeigt.

using System;
using System.Globalization;
using System.Text;

public class Example3
{
    public static void Main()
    {
        Random rnd = new Random();
        StringBuilder sb = new StringBuilder();

        // Generate 10 random numbers and store them in a StringBuilder.
        for (int ctr = 0; ctr <= 9; ctr++)
            sb.Append(rnd.Next().ToString("N5"));

        Console.WriteLine("The original string:");
        Console.WriteLine(sb.ToString());

        // Decrease each number by one.
        for (int ctr = 0; ctr < sb.Length; ctr++)
        {
            if (Char.GetUnicodeCategory(sb[ctr]) == UnicodeCategory.DecimalDigitNumber)
            {
                int number = (int)Char.GetNumericValue(sb[ctr]);
                number--;
                if (number < 0) number = 9;

                sb[ctr] = number.ToString()[0];
            }
        }
        Console.WriteLine("\nThe new string:");
        Console.WriteLine(sb.ToString());
    }
}
// The example displays the following output:
//    The original string:
//    1,457,531,530.00000940,522,609.000001,668,113,564.000001,998,992,883.000001,792,660,834.00
//    000101,203,251.000002,051,183,075.000002,066,000,067.000001,643,701,043.000001,702,382,508
//    .00000
//    
//    The new string:
//    0,346,420,429.99999839,411,598.999990,557,002,453.999990,887,881,772.999990,681,559,723.99
//    999090,192,140.999991,940,072,964.999991,955,999,956.999990,532,690,932.999990,691,271,497
//    .99999
open System
open System.Globalization
open System.Text

let rnd = Random()
let sb = new StringBuilder()

// Generate 10 random numbers and store them in a StringBuilder.
for _ = 0 to 9 do
    rnd.Next().ToString "N5" |> sb.Append |> ignore

printfn "The original string:"
printfn $"{sb}"

// Decrease each number by one.
for i = 0 to sb.Length - 1 do
    if Char.GetUnicodeCategory(sb[i]) = UnicodeCategory.DecimalDigitNumber then
        let number = Char.GetNumericValue sb.[i] |> int
        let number = number - 1
        let number = if number < 0 then 9 else number
        sb.[i] <- number.ToString()[0]

printfn "\nThe new string:"
printfn $"{sb}"

// The example displays the following output:
//    The original string:
//    1,457,531,530.00000940,522,609.000001,668,113,564.000001,998,992,883.000001,792,660,834.00
//    000101,203,251.000002,051,183,075.000002,066,000,067.000001,643,701,043.000001,702,382,508
//    .00000
//
//    The new string:
//    0,346,420,429.99999839,411,598.999990,557,002,453.999990,887,881,772.999990,681,559,723.99
//    999090,192,140.999991,940,072,964.999991,955,999,956.999990,532,690,932.999990,691,271,497
//    .99999
Imports System.Globalization
Imports System.Text

Module Example4
    Public Sub Main()
        Dim rnd As New Random()
        Dim sb As New StringBuilder()

        ' Generate 10 random numbers and store them in a StringBuilder.
        For ctr As Integer = 0 To 9
            sb.Append(rnd.Next().ToString("N5"))
        Next
        Console.WriteLine("The original string:")
        Console.WriteLine(sb.ToString())
        Console.WriteLine()

        ' Decrease each number by one.
        For ctr As Integer = 0 To sb.Length - 1
            If Char.GetUnicodeCategory(sb(ctr)) = UnicodeCategory.DecimalDigitNumber Then
                Dim number As Integer = CType(Char.GetNumericValue(sb(ctr)), Integer)
                number -= 1
                If number < 0 Then number = 9

                sb(ctr) = number.ToString()(0)
            End If
        Next
        Console.WriteLine("The new string:")
        Console.WriteLine(sb.ToString())
    End Sub
End Module
' The example displays the following output:
'    The original string:
'    1,457,531,530.00000940,522,609.000001,668,113,564.000001,998,992,883.000001,792,660,834.00
'    000101,203,251.000002,051,183,075.000002,066,000,067.000001,643,701,043.000001,702,382,508
'    .00000
'    
'    The new string:
'    0,346,420,429.99999839,411,598.999990,557,002,453.999990,887,881,772.999990,681,559,723.99
'    999090,192,140.999991,940,072,964.999991,955,999,956.999990,532,690,932.999990,691,271,497
'    .99999

Das Verwenden von zeichenbasierter Indizierung mit der Chars[]-Eigenschaft kann unter folgenden Bedingungen sehr langsam sein:

Die Leistung wird erheblich beeinträchtigt, da für jeden Zugriff auf ein Zeichen die gesamte verknüpfte Liste der Blöcke durchlaufen wird, um den richtigen Puffer für die Indizierung zu suchen.

Hinweis

Selbst für ein großes "chunky" StringBuilder -Objekt hat die Verwendung der Eigenschaft für den Chars[] indexbasierten Zugriff auf einen oder eine kleine Anzahl von Zeichen eine vernachlässigbare Leistungsauswirkung. In der Regel handelt es sich um einen O(n) -Vorgang. Diese erheblichen Auswirkungen auf die Leistung treten auf, wenn die Zeichen im StringBuilder-Objekt durchlaufen werden. Dabei handelt es sich um eine O(n^2)-Operation.

Wenn Leistungsprobleme auftreten, wenn Sie die zeichenbasierte Indizierung mit StringBuilder-Objekten verwenden, können Sie eine der folgenden Problemumgehungen anwenden:

  • Konvertieren Sie die StringBuilder-Instanz zu String, indem Sie die ToString-Methode aufrufen. Greifen Sie dann auf die Zeichen in der Zeichenfolge zu.

  • Kopieren Sie die Inhalte des vorhandenen StringBuilder-Objekts in ein neues StringBuilder-Objekt mit vorab festgelegter Größe. Die Leistung verbessert sich, da das neue StringBuilder-Objekt nicht „blockweise“ strukturiert ist. Beispiel:

    // sbOriginal is the existing StringBuilder object
    var sbNew = new StringBuilder(sbOriginal.ToString(), sbOriginal.Length);
    
    ' sbOriginal is the existing StringBuilder object
    Dim sbNew = New StringBuilder(sbOriginal.ToString(), sbOriginal.Length)
    
  • Legen Sie die anfängliche Kapazität des StringBuilder-Objekts auf einen Wert fest, der ungefähr der maximal erwarteten Größe entspricht, indem der StringBuilder(Int32)-Konstruktor aufgerufen wird. Beachten Sie, dass dadurch der gesamte Arbeitsspeicherblock zugeordnet wird, auch wenn StringBuilder selten die maximale Kapazität erreicht.

Hinzufügen von Text zu einem StringBuilder-Objekt

Die StringBuilder Klasse enthält die folgenden Methoden zum Erweitern des Inhalts eines StringBuilder Objekts:

  • Die Append Methode fügt eine Zeichenfolge, eine Teilzeichenfolge, ein Zeichenarray, einen Teil eines Zeichenarrays, ein einzelnes Zeichen mehrmals wiederholt oder die Zeichenfolgendarstellung eines primitiven Datentyps an ein StringBuilder Objekt an.

  • Die AppendLine Methode fügt einen Zeilenterminator oder eine Zeichenfolge zusammen mit einem Zeilenterminator an ein StringBuilder Objekt an.

  • Die AppendFormat Methode fügt eine zusammengesetzte Formatzeichenfolge an ein StringBuilder Objekt an. Die Zeichenfolgendarstellungen von Objekten, die in der Ergebniszeichenfolge enthalten sind, können die Formatierungskonventionen der aktuellen Systemkultur oder einer angegebenen Kultur widerspiegeln.

  • Die Insert Methode fügt eine Zeichenfolge, eine Teilzeichenfolge, mehrere Wiederholungen einer Zeichenfolge, ein Zeichenarray, einen Teil eines Zeichenarrays oder die Zeichenfolgendarstellung eines primitiven Datentyps an einer angegebenen Position im StringBuilder Objekt ein. Die Position wird durch einen nullbasierten Index definiert.

Im folgenden Beispiel werden der Text eines StringBuilder Objekts mithilfe der AppendMethoden , AppendLine, , AppendFormatund Insert die Methoden erweitert.

using System;
using System.Text;

public class Example6
{
    public static void Main()
    {
        // Create a StringBuilder object with no text.
        StringBuilder sb = new StringBuilder();
        // Append some text.
        sb.Append('*', 10).Append(" Adding Text to a StringBuilder Object ").Append('*', 10);
        sb.AppendLine("\n");
        sb.AppendLine("Some code points and their corresponding characters:");
        // Append some formatted text.
        for (int ctr = 50; ctr <= 60; ctr++)
        {
            sb.AppendFormat("{0,12:X4} {1,12}", ctr, Convert.ToChar(ctr));
            sb.AppendLine();
        }
        // Find the end of the introduction to the column.
        int pos = sb.ToString().IndexOf("characters:") + 11 +
                  Environment.NewLine.Length;
        // Insert a column header.
        sb.Insert(pos, String.Format("{2}{0,12:X4} {1,12}{2}", "Code Unit",
                                     "Character", "\n"));

        // Convert the StringBuilder to a string and display it.      
        Console.WriteLine(sb.ToString());
    }
}
// The example displays the following output:
//    ********** Adding Text to a StringBuilder Object **********
//    
//    Some code points and their corresponding characters:
//    
//       Code Unit    Character
//            0032            2
//            0033            3
//            0034            4
//            0035            5
//            0036            6
//            0037            7
//            0038            8
//            0039            9
//            003A            :
//            003B            ;
//            003C            <
open System
open System.Text

// Create a StringBuilder object with no text.
let sb = StringBuilder()
// Append some text.
sb
    .Append('*', 10)
    .Append(" Adding Text to a StringBuilder Object ")
    .Append('*', 10)
|> ignore

sb.AppendLine "\n" |> ignore
sb.AppendLine "Some code points and their corresponding characters:" |> ignore
// Append some formatted text.
for i = 50 to 60 do
    sb.AppendFormat("{0,12:X4} {1,12}", i, Convert.ToChar i) |> ignore
    sb.AppendLine() |> ignore

// Find the end of the introduction to the column.
let pos = (string sb).IndexOf("characters:") + 11 + Environment.NewLine.Length
// Insert a column header.
sb.Insert(pos, String.Format("{2}{0,12:X4} {1,12}{2}", "Code Unit", "Character", "\n"))
|> ignore

// Convert the StringBuilder to a string and display it.
printfn $"{sb}"


// The example displays the following output:
//    ********** Adding Text to a StringBuilder Object **********
//
//    Some code points and their corresponding characters:
//
//       Code Unit    Character
//            0032            2
//            0033            3
//            0034            4
//            0035            5
//            0036            6
//            0037            7
//            0038            8
//            0039            9
//            003A            :
//            003B            ;
//            003C            <
Imports System.Text

Module Example7
    Public Sub Main()
        ' Create a StringBuilder object with no text.
        Dim sb As New StringBuilder()
        ' Append some text.
        sb.Append("*"c, 10).Append(" Adding Text to a StringBuilder Object ").Append("*"c, 10)
        sb.AppendLine()
        sb.AppendLine()
        sb.AppendLine("Some code points and their corresponding characters:")
        ' Append some formatted text.
        For ctr = 50 To 60
            sb.AppendFormat("{0,12:X4} {1,12}", ctr, Convert.ToChar(ctr))
            sb.AppendLine()
        Next
        ' Find the end of the introduction to the column.
        Dim pos As Integer = sb.ToString().IndexOf("characters:") + 11 +
                           Environment.NewLine.Length
        ' Insert a column header.
        sb.Insert(pos, String.Format("{2}{0,12:X4} {1,12}{2}", "Code Unit",
                                   "Character", vbCrLf))

        ' Convert the StringBuilder to a string and display it.      
        Console.WriteLine(sb.ToString())
    End Sub
End Module
' The example displays the following output:
'       ********** Adding Text to a StringBuilder Object **********
'       
'       Some code points and their corresponding characters:
'       
'          Code Unit    Character
'               0032            2
'               0033            3
'               0034            4
'               0035            5
'               0036            6
'               0037            7
'               0038            8
'               0039            9
'               003A            :
'               003B            ;
'               003C            <

Löschen von Text aus einem StringBuilder-Objekt

Die StringBuilder Klasse enthält Methoden, mit denen die Größe der aktuellen StringBuilder Instanz reduziert werden kann. Die Clear Methode entfernt alle Zeichen und legt die Length Eigenschaft auf Null fest. Die Remove Methode löscht eine angegebene Anzahl von Zeichen, die an einer bestimmten Indexposition beginnen. Darüber hinaus können Sie Zeichen vom Ende eines StringBuilder Objekts entfernen, indem Sie dessen Length Eigenschaft auf einen Wert festlegen, der kleiner als die Länge der aktuellen Instanz ist.

Im folgenden Beispiel wird ein Teil des Texts aus einem StringBuilder Objekt entfernt, die resultierende Kapazität, die maximale Kapazität und die Länge der Eigenschaftswerte angezeigt, und anschließend wird die Clear Methode aufgerufen, um alle Zeichen aus dem StringBuilder Objekt zu entfernen.

using System;
using System.Text;

public class Example5
{
    public static void Main()
    {
        StringBuilder sb = new StringBuilder("A StringBuilder object");
        ShowSBInfo(sb);
        // Remove "object" from the text.
        string textToRemove = "object";
        int pos = sb.ToString().IndexOf(textToRemove);
        if (pos >= 0)
        {
            sb.Remove(pos, textToRemove.Length);
            ShowSBInfo(sb);
        }
        // Clear the StringBuilder contents.
        sb.Clear();
        ShowSBInfo(sb);
    }

    public static void ShowSBInfo(StringBuilder sb)
    {
        Console.WriteLine("\nValue: {0}", sb.ToString());
        foreach (var prop in sb.GetType().GetProperties())
        {
            if (prop.GetIndexParameters().Length == 0)
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb));
        }
        Console.WriteLine();
    }
}
// The example displays the following output:
//    Value: A StringBuilder object
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 22
//    
//    Value: A StringBuilder
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 16
//    
//    Value:
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 0
open System.Text

let showSBInfo (sb: StringBuilder) =
    for prop in sb.GetType().GetProperties() do
        if prop.GetIndexParameters().Length = 0 then
            printf $"{prop.Name}: {prop.GetValue sb:N0}    "

    printfn ""

let sb = StringBuilder "A StringBuilder object"
showSBInfo sb
// Remove "object" from the text.
let textToRemove = "object"
let pos = (string sb).IndexOf textToRemove

if pos >= 0 then
    sb.Remove(pos, textToRemove.Length) |> ignore
    showSBInfo sb

// Clear the StringBuilder contents.
sb.Clear() |> ignore
showSBInfo sb

// The example displays the following output:
//    Value: A StringBuilder object
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 22
//
//    Value: A StringBuilder
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 16
//
//    Value:
//    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 0
Imports System.Text

Module Example6
    Public Sub Main()
        Dim sb As New StringBuilder("A StringBuilder object")
        ShowSBInfo(sb)
        ' Remove "object" from the text.
        Dim textToRemove As String = "object"
        Dim pos As Integer = sb.ToString().IndexOf(textToRemove)
        If pos >= 0 Then
            sb.Remove(pos, textToRemove.Length)
            ShowSBInfo(sb)
        End If
        ' Clear the StringBuilder contents.
        sb.Clear()
        ShowSBInfo(sb)
    End Sub

    Public Sub ShowSBInfo(sb As StringBuilder)
        Console.WriteLine()
        Console.WriteLine("Value: {0}", sb.ToString())
        For Each prop In sb.GetType().GetProperties
            If prop.GetIndexParameters().Length = 0 Then
                Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb))
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' The example displays the following output:
'    Value: A StringBuilder object
'    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 22
'    
'    Value: A StringBuilder
'    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 16
'    
'    Value:
'    Capacity: 22    MaxCapacity: 2,147,483,647    Length: 0

Ändern des Texts in einem StringBuilder-Objekt

Die StringBuilder.Replace Methode ersetzt alle Vorkommen eines Zeichens oder einer Zeichenfolge im gesamten StringBuilder Objekt oder in einem bestimmten Zeichenbereich. Im folgenden Beispiel wird die Replace Methode verwendet, um alle Ausrufezeichen (!) durch Fragezeichen (?) im StringBuilder Objekt zu ersetzen.

using System;
using System.Text;

public class Example13
{
    public static void Main()
    {
        StringBuilder MyStringBuilder = new StringBuilder("Hello World!");
        MyStringBuilder.Replace('!', '?');
        Console.WriteLine(MyStringBuilder);
    }
}
// The example displays the following output:
//       Hello World?
open System.Text

let myStringBuilder = StringBuilder "Hello World!"
myStringBuilder.Replace('!', '?') |> ignore
printfn $"{myStringBuilder}"

// The example displays the following output:
//       Hello World?
Imports System.Text

Module Example
   Public Sub Main()
      Dim MyStringBuilder As New StringBuilder("Hello World!")
      MyStringBuilder.Replace("!"c, "?"c)
      Console.WriteLine(MyStringBuilder)
   End Sub
End Module
' The example displays the following output:
'       Hello World?

Durchsuchen des Texts in einem StringBuilder-Objekt

Die StringBuilder Klasse enthält keine Methoden, die den String.ContainsString.IndexOfvon der String Klasse bereitgestellten Methoden ähneln, und String.StartsWith ermöglicht es Ihnen, das Objekt nach einem bestimmten Zeichen oder einer Teilzeichenfolge zu durchsuchen. Zum Ermitteln der Anwesenheits- oder Startzeichenposition einer Teilzeichenfolge müssen Sie einen String Wert mithilfe einer Zeichenfolgensuchmethode oder einer regulären Ausdrucksmethode durchsuchen. Es gibt vier Möglichkeiten zum Implementieren solcher Suchvorgänge, wie in der folgenden Tabelle dargestellt.

Verfahren Vorteile Nachteile
Suchen Sie Zeichenfolgenwerte, bevor Sie sie dem StringBuilder Objekt hinzufügen. Nützlich, um zu bestimmen, ob eine Teilzeichenfolge vorhanden ist. Kann nicht verwendet werden, wenn die Indexposition einer Teilzeichenfolge wichtig ist.
Rufen Sie ToString das zurückgegebene Objekt auf String , und durchsuchen Sie es. Einfach zu verwenden, wenn Sie den gesamten Text einem StringBuilder Objekt zuweisen und dann mit der Änderung beginnen. Umständlich, wiederholt aufzurufen ToString , wenn Sie Änderungen vornehmen müssen, bevor der gesamte Text dem StringBuilder Objekt hinzugefügt wird.

Sie müssen daran denken, am Ende des Texts des StringBuilder Objekts zu arbeiten, wenn Sie Änderungen vornehmen.
Verwenden Sie die Chars[] Eigenschaft, um einen Bereich von Zeichen sequenziell zu durchsuchen. Nützlich, wenn Sie sich mit einzelnen Zeichen oder einer kleinen Teilzeichenfolge befassen. Umständlich, wenn die Anzahl der zu durchsuchenden Zeichen groß ist oder die Suchlogik komplex ist.

Führt zu einer sehr schlechten Leistung für Objekte, die durch wiederholte Methodenaufrufe sehr groß geworden sind.
Konvertieren Sie das StringBuilder Objekt in ein String Objekt, und führen Sie Änderungen am String Objekt aus. Nützlich, wenn die Anzahl der Änderungen klein ist. Hebt den Leistungsvorteil der StringBuilder Klasse auf, wenn die Anzahl der Änderungen groß ist.

Lassen Sie uns diese Techniken genauer untersuchen.

  • Wenn das Ziel der Suche darin besteht, zu bestimmen, ob eine bestimmte Teilzeichenfolge vorhanden ist (d. h., wenn Sie nicht an der Position der Teilzeichenfolge interessiert sind), können Sie Zeichenfolgen durchsuchen, bevor Sie sie im StringBuilder Objekt speichern. Im folgenden Beispiel wird eine mögliche Implementierung bereitgestellt. Es definiert eine StringBuilderFinder Klasse, deren Konstruktor einen Verweis auf ein StringBuilder Objekt und die Teilzeichenfolge übergeben wird, um in der Zeichenfolge zu suchen. In diesem Fall versucht das Beispiel zu bestimmen, ob sich aufgezeichnete Temperaturen in Fahrenheit oder Celsius befinden, und fügt den entsprechenden Einleitungstext am Anfang des StringBuilder Objekts hinzu. Ein Zufallszahlengenerator wird verwendet, um ein Array auszuwählen, das Daten in Grad Celsius oder Grad Fahrenheit enthält.

    using System;
    using System.Text;
    
    public class Example9
    {
        public static void Main()
        {
            Random rnd = new Random();
            string[] tempF = { "47.6F", "51.3F", "49.5F", "62.3F" };
            string[] tempC = { "21.2C", "16.1C", "23.5C", "22.9C" };
            string[][] temps = { tempF, tempC };
    
            StringBuilder sb = new StringBuilder();
            var f = new StringBuilderFinder(sb, "F");
            var baseDate = new DateTime(2013, 5, 1);
            String[] temperatures = temps[rnd.Next(2)];
            bool isFahrenheit = false;
            foreach (var temperature in temperatures)
            {
                if (isFahrenheit)
                    sb.AppendFormat("{0:d}: {1}\n", baseDate, temperature);
                else
                    isFahrenheit = f.SearchAndAppend(String.Format("{0:d}: {1}\n",
                                                     baseDate, temperature));
                baseDate = baseDate.AddDays(1);
            }
            if (isFahrenheit)
            {
                sb.Insert(0, "Average Daily Temperature in Degrees Fahrenheit");
                sb.Insert(47, "\n\n");
            }
            else
            {
                sb.Insert(0, "Average Daily Temperature in Degrees Celsius");
                sb.Insert(44, "\n\n");
            }
            Console.WriteLine(sb.ToString());
        }
    }
    
    public class StringBuilderFinder
    {
        private StringBuilder sb;
        private String text;
    
        public StringBuilderFinder(StringBuilder sb, String textToFind)
        {
            this.sb = sb;
            this.text = textToFind;
        }
    
        public bool SearchAndAppend(String stringToSearch)
        {
            sb.Append(stringToSearch);
            return stringToSearch.Contains(text);
        }
    }
    // The example displays output similar to the following:
    //    Average Daily Temperature in Degrees Celsius
    //    
    //    5/1/2013: 21.2C
    //    5/2/2013: 16.1C
    //    5/3/2013: 23.5C
    //    5/4/2013: 22.9C
    
    open System
    open System.Text
    
    type StringBuilderFinder(sb: StringBuilder, textToFind: string) =
        member _.SearchAndAppend(stringToSearch: string) =
            sb.Append stringToSearch |> ignore
            stringToSearch.Contains textToFind
    
    let tempF = [| "47.6F"; "51.3F"; "49.5F"; "62.3F" |]
    let tempC = [| "21.2C"; "16.1C"; "23.5C"; "22.9C" |]
    let temps = [| tempF; tempC |]
    
    let sb = StringBuilder()
    let f = StringBuilderFinder(sb, "F")
    let temperatures = temps[Random.Shared.Next(2)]
    let mutable baseDate = DateTime(2013, 5, 1)
    let mutable isFahrenheit = false
    
    for temperature in temperatures do
        if isFahrenheit then
            sb.AppendFormat("{0:d}: {1}\n", baseDate, temperature) |> ignore
        else
            isFahrenheit <- $"{baseDate:d}: {temperature}\n" |> f.SearchAndAppend
    
        baseDate <- baseDate.AddDays 1
    
    if isFahrenheit then
        sb.Insert(0, "Average Daily Temperature in Degrees Fahrenheit") |> ignore
        sb.Insert(47, "\n\n") |> ignore
    
    else
        sb.Insert(0, "Average Daily Temperature in Degrees Celsius") |> ignore
        sb.Insert(44, "\n\n") |> ignore
    
    printfn $"{sb}"
    
    // The example displays output similar to the following:
    //    Average Daily Temperature in Degrees Celsius
    //
    //    5/1/2013: 21.2C
    //    5/2/2013: 16.1C
    //    5/3/2013: 23.5C
    //    5/4/2013: 22.9C
    
    Imports System.Text
    
    Module Example9
        Public Sub Main()
            Dim rnd As New Random()
            Dim tempF() As String = {"47.6F", "51.3F", "49.5F", "62.3F"}
            Dim tempC() As String = {"21.2C", "16.1C", "23.5C", "22.9C"}
            Dim temps()() As String = {tempF, tempC}
    
            Dim sb As StringBuilder = New StringBuilder()
            Dim f As New StringBuilderFinder(sb, "F")
            Dim baseDate As New DateTime(2013, 5, 1)
            Dim temperatures() As String = temps(rnd.Next(2))
            Dim isFahrenheit As Boolean = False
            For Each temperature In temperatures
                If isFahrenheit Then
                    sb.AppendFormat("{0:d}: {1}{2}", baseDate, temperature, vbCrLf)
                Else
                    isFahrenheit = f.SearchAndAppend(String.Format("{0:d}: {1}{2}",
                                                 baseDate, temperature, vbCrLf))
                End If
                baseDate = baseDate.AddDays(1)
            Next
            If isFahrenheit Then
                sb.Insert(0, "Average Daily Temperature in Degrees Fahrenheit")
                sb.Insert(47, vbCrLf + vbCrLf)
            Else
                sb.Insert(0, "Average Daily Temperature in Degrees Celsius")
                sb.Insert(44, vbCrLf + vbCrLf)
            End If
            Console.WriteLine(sb.ToString())
        End Sub
    End Module
    
    Public Class StringBuilderFinder
       Private sb As StringBuilder
       Private text As String
       
       Public Sub New(sb As StringBuilder, textToFind As String)
          Me.sb = sb
          text = textToFind
       End Sub
       
       Public Function SearchAndAppend(stringToSearch As String) As Boolean
          sb.Append(stringToSearch)
          Return stringToSearch.Contains(text)
       End Function
    End Class
    ' The example displays output similar to the following:
    '    Average Daily Temperature in Degrees Celsius
    '    
    '    5/1/2013: 21.2C
    '    5/2/2013: 16.1C
    '    5/3/2013: 23.5C
    '    5/4/2013: 22.9C
    
  • Rufen Sie die StringBuilder.ToString Methode auf, um das StringBuilder Objekt in ein String Objekt zu konvertieren. Sie können die Zeichenfolge mithilfe von Methoden wie String.LastIndexOf oder String.StartsWith, oder Sie können reguläre Ausdrücke und die Regex Klasse verwenden, um nach Mustern zu suchen. Da sowohl als String auch StringBuilder Objekte UTF-16-Codierung zum Speichern von Zeichen verwenden, sind die Indexpositionen von Zeichen, Teilzeichenfolgen und Übereinstimmungen mit regulären Ausdrücken in beiden Objekten identisch. Auf diese Weise können Sie Methoden verwenden StringBuilder , um Änderungen an derselben Position vorzunehmen, an der sich dieser Text im String Objekt befindet.

    Hinweis

    Wenn Sie diesen Ansatz übernehmen, sollten Sie vom Ende des StringBuilder Objekts bis zum Anfang arbeiten, damit Sie das StringBuilder Objekt nicht wiederholt in eine Zeichenfolge konvertieren müssen.

    Dieser Ansatz wird anhand des folgenden Beispiels veranschaulicht. Es speichert vier Vorkommen jedes Buchstabens des englischen Alphabets in einem StringBuilder Objekt. Anschließend wird der Text in ein String Objekt konvertiert und ein regulärer Ausdruck verwendet, um die Anfangsposition jeder vierstelligen Sequenz zu identifizieren. Schließlich wird vor jeder vierstelligen Sequenz mit Ausnahme der ersten Sequenz ein Unterstrich hinzugefügt und das erste Zeichen der Sequenz in Großbuchstaben konvertiert.

    using System;
    using System.Text;
    using System.Text.RegularExpressions;
    
    public class Example10
    {
        public static void Main()
        {
            // Create a StringBuilder object with 4 successive occurrences 
            // of each character in the English alphabet. 
            StringBuilder sb = new StringBuilder();
            for (ushort ctr = (ushort)'a'; ctr <= (ushort)'z'; ctr++)
                sb.Append(Convert.ToChar(ctr), 4);
    
            // Create a parallel string object.
            String sbString = sb.ToString();
            // Determine where each new character sequence begins.
            String pattern = @"(\w)\1+";
            MatchCollection matches = Regex.Matches(sbString, pattern);
    
            // Uppercase the first occurrence of the sequence, and separate it
            // from the previous sequence by an underscore character.
            for (int ctr = matches.Count - 1; ctr >= 0; ctr--)
            {
                Match m = matches[ctr];
                sb[m.Index] = Char.ToUpper(sb[m.Index]);
                if (m.Index > 0) sb.Insert(m.Index, "_");
            }
            // Display the resulting string.
            sbString = sb.ToString();
            int line = 0;
            do
            {
                int nChars = line * 80 + 79 <= sbString.Length ?
                                    80 : sbString.Length - line * 80;
                Console.WriteLine(sbString.Substring(line * 80, nChars));
                line++;
            } while (line * 80 < sbString.Length);
        }
    }
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    open System
    open System.Text
    open System.Text.RegularExpressions
    
    // Create a StringBuilder object with 4 successive occurrences
    // of each character in the English alphabet.
    let sb = StringBuilder()
    
    for char in 'a' .. 'z' do
        sb.Append(char, 4) |> ignore
    
    // Create a parallel string object.
    let sbString = string sb
    // Determine where each new character sequence begins.
    let pattern = @"(\w)\1+"
    let matches = Regex.Matches(sbString, pattern)
    
    // Uppercase the first occurrence of the sequence, and separate it
    // from the previous sequence by an underscore character.
    for i = matches.Count - 1 downto 0 do
        let m = matches[i]
        sb[m.Index] <- Char.ToUpper sb[m.Index]
    
        if m.Index > 0 then
            sb.Insert(m.Index, "_") |> ignore
    
    // Display the resulting string.
    let sbString2 = string sb
    
    for line = 0 to (sbString2.Length - 1) / 80 do
        let nChars =
            if line * 80 + 79 <= sbString2.Length then
                80
            else
                sbString2.Length - line * 80
    
        printfn $"{sbString2.Substring(line * 80, nChars)}"
    
    
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    Imports System.Text
    Imports System.Text.RegularExpressions
    
    Module Example10
        Public Sub Main()
            ' Create a StringBuilder object with 4 successive occurrences 
            ' of each character in the English alphabet. 
            Dim sb As New StringBuilder()
            For ctr As UShort = AscW("a") To AscW("z")
                sb.Append(ChrW(ctr), 4)
            Next
            ' Create a parallel string object.
            Dim sbString As String = sb.ToString()
            ' Determine where each new character sequence begins.
            Dim pattern As String = "(\w)\1+"
            Dim matches As MatchCollection = Regex.Matches(sbString, pattern)
    
            ' Uppercase the first occurrence of the sequence, and separate it
            ' from the previous sequence by an underscore character.
            For ctr As Integer = matches.Count - 1 To 0 Step -1
                Dim m As Match = matches(ctr)
                sb.Chars(m.Index) = Char.ToUpper(sb.Chars(m.Index))
                If m.Index > 0 Then sb.Insert(m.Index, "_")
            Next
            ' Display the resulting string.
            sbString = sb.ToString()
            Dim line As Integer = 0
            Do
                Dim nChars As Integer = If(line * 80 + 79 <= sbString.Length,
                                        80, sbString.Length - line * 80)
                Console.WriteLine(sbString.Substring(line * 80, nChars))
                line += 1
            Loop While line * 80 < sbString.Length
        End Sub
    End Module
    ' The example displays the following output:
    '    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    '    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
  • Verwenden Sie die StringBuilder.Chars[] Eigenschaft, um einen Bereich von Zeichen in einem StringBuilder Objekt sequenziell zu durchsuchen. Dieser Ansatz ist möglicherweise nicht praktisch, wenn die Anzahl der zu durchsuchenden Zeichen groß ist oder die Suchlogik besonders komplex ist. Die Leistungsauswirkungen des zeichenbasierten indexbasierten Zugriffs für sehr große, geblockte StringBuilder Objekte finden Sie in der Dokumentation für die StringBuilder.Chars[] Eigenschaft.

    Das folgende Beispiel ist identisch mit der Funktionalität des vorherigen Beispiels, unterscheidet sich jedoch in der Implementierung. Sie verwendet die Chars[] Eigenschaft, um zu erkennen, wann ein Zeichenwert geändert wurde, einen Unterstrich an dieser Position einfügt und das erste Zeichen in der neuen Sequenz in Großbuchstaben konvertiert.

    using System;
    using System.Text;
    
    public class Example11
    {
        public static void Main()
        {
            // Create a StringBuilder object with 4 successive occurrences 
            // of each character in the English alphabet. 
            StringBuilder sb = new StringBuilder();
            for (ushort ctr = (ushort)'a'; ctr <= (ushort)'z'; ctr++)
                sb.Append(Convert.ToChar(ctr), 4);
    
            // Iterate the text to determine when a new character sequence occurs.
            int position = 0;
            Char current = '\u0000';
            do
            {
                if (sb[position] != current)
                {
                    current = sb[position];
                    sb[position] = Char.ToUpper(sb[position]);
                    if (position > 0)
                        sb.Insert(position, "_");
                    position += 2;
                }
                else
                {
                    position++;
                }
            } while (position <= sb.Length - 1);
            // Display the resulting string.
            String sbString = sb.ToString();
            int line = 0;
            do
            {
                int nChars = line * 80 + 79 <= sbString.Length ?
                                    80 : sbString.Length - line * 80;
                Console.WriteLine(sbString.Substring(line * 80, nChars));
                line++;
            } while (line * 80 < sbString.Length);
        }
    }
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    open System
    open System.Text
    
    // Create a StringBuilder object with 4 successive occurrences
    // of each character in the English alphabet.
    let sb = StringBuilder()
    
    for char in 'a' .. 'z' do
        sb.Append(char, 4) |> ignore
    
    // Iterate the text to determine when a new character sequence occurs.
    let mutable position = 0
    let mutable current = '\u0000'
    
    while position <= sb.Length - 1 do
        if sb[position] <> current then
            current <- sb[position]
            sb[position] <- Char.ToUpper sb[position]
    
            if position > 0 then
                sb.Insert(position, "_") |> ignore
    
            position <- position + 2
    
        else
            position <- position + 1
    
    // Display the resulting string.
    let sbString = string sb
    
    for line = 0 to (sbString.Length - 1) / 80 do
        let nChars =
            if line * 80 + 79 <= sbString.Length then
                80
            else
                sbString.Length - line * 80
    
        printfn $"{sbString.Substring(line * 80, nChars)}"
    
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    Imports System.Text
    
    Module Example11
        Public Sub Main()
            ' Create a StringBuilder object with 4 successive occurrences 
            ' of each character in the English alphabet. 
            Dim sb As New StringBuilder()
            For ctr As UShort = AscW("a") To AscW("z")
                sb.Append(ChrW(ctr), 4)
            Next
            ' Iterate the text to determine when a new character sequence occurs.
            Dim position As Integer = 0
            Dim current As Char = ChrW(0)
            Do
                If sb(position) <> current Then
                    current = sb(position)
                    sb(position) = Char.ToUpper(sb(position))
                    If position > 0 Then sb.Insert(position, "_")
                    position += 2
                Else
                    position += 1
                End If
            Loop While position <= sb.Length - 1
            ' Display the resulting string.
            Dim sbString As String = sb.ToString()
            Dim line As Integer = 0
            Do
                Dim nChars As Integer = If(line * 80 + 79 <= sbString.Length,
                                        80, sbString.Length - line * 80)
                Console.WriteLine(sbString.Substring(line * 80, nChars))
                line += 1
            Loop While line * 80 < sbString.Length
        End Sub
    End Module
    ' The example displays the following output:
    '    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    '    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
  • Speichern Sie den gesamten unveränderten Text im StringBuilder Objekt, rufen Sie die StringBuilder.ToString Methode auf, um das StringBuilder Objekt in ein String Objekt zu konvertieren, und führen Sie die Änderungen für das String Objekt aus. Sie können diesen Ansatz verwenden, wenn Sie nur wenige Änderungen haben. andernfalls können die Kosten für die Arbeit mit unveränderlichen Zeichenfolgen die Leistungsvorteile der Verwendung eines StringBuilder Objekts aufheben.

    Das folgende Beispiel ist in der Funktionalität mit den beiden vorherigen Beispielen identisch, unterscheidet sich jedoch in der Implementierung. Es erstellt ein StringBuilder Objekt, konvertiert es in ein String Objekt und verwendet dann einen regulären Ausdruck, um alle Änderungen an der Zeichenfolge auszuführen Standard. Die Regex.Replace(String, String, MatchEvaluator) Methode verwendet einen Lambda-Ausdruck, um den Ersatz für jede Übereinstimmung auszuführen.

    using System;
    using System.Text;
    using System.Text.RegularExpressions;
    
    public class Example12
    {
        public static void Main()
        {
            // Create a StringBuilder object with 4 successive occurrences 
            // of each character in the English alphabet. 
            StringBuilder sb = new StringBuilder();
            for (ushort ctr = (ushort)'a'; ctr <= (ushort)'z'; ctr++)
                sb.Append(Convert.ToChar(ctr), 4);
    
            // Convert it to a string.
            String sbString = sb.ToString();
    
            // Use a regex to uppercase the first occurrence of the sequence, 
            // and separate it from the previous sequence by an underscore.
            string pattern = @"(\w)(\1+)";
            sbString = Regex.Replace(sbString, pattern,
                                     m => (m.Index > 0 ? "_" : "") +
                                     m.Groups[1].Value.ToUpper() +
                                     m.Groups[2].Value);
    
            // Display the resulting string.
            int line = 0;
            do
            {
                int nChars = line * 80 + 79 <= sbString.Length ?
                                    80 : sbString.Length - line * 80;
                Console.WriteLine(sbString.Substring(line * 80, nChars));
                line++;
            } while (line * 80 < sbString.Length);
        }
    }
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    open System.Text
    open System.Text.RegularExpressions
    
    // Create a StringBuilder object with 4 successive occurrences
    // of each character in the English alphabet.
    let sb = StringBuilder()
    
    for char in 'a' .. 'z' do
        sb.Append(char, 4) |> ignore
    
    // Convert it to a string.
    let sbString = string sb
    
    // Use a regex to uppercase the first occurrence of the sequence,
    // and separate it from the previous sequence by an underscore.
    let pattern = @"(\w)(\1+)"
    
    let sbStringReplaced =
        Regex.Replace(
            sbString,
            pattern,
            fun m ->
                (if m.Index > 0 then "_" else "")
                + m.Groups[ 1 ].Value.ToUpper()
                + m.Groups[2].Value
        )
    
    // Display the resulting string.
    for line = 0 to (sbStringReplaced.Length - 1) / 80 do
        let nChars =
            if line * 80 + 79 <= sbStringReplaced.Length then
                80
            else
                sbStringReplaced.Length - line * 80
    
        printfn $"{sbStringReplaced.Substring(line * 80, nChars)}"
    
    // The example displays the following output:
    //    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    //    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    
    Imports System.Text
    Imports System.Text.RegularExpressions
    
    Module Example12
        Public Sub Main()
            ' Create a StringBuilder object with 4 successive occurrences 
            ' of each character in the English alphabet. 
            Dim sb As New StringBuilder()
            For ctr As UShort = AscW("a") To AscW("z")
                sb.Append(ChrW(ctr), 4)
            Next
            ' Convert it to a string.
            Dim sbString As String = sb.ToString()
    
            ' Use a regex to uppercase the first occurrence of the sequence, 
            ' and separate it from the previous sequence by an underscore.
            Dim pattern As String = "(\w)(\1+)"
            sbString = Regex.Replace(sbString, pattern,
                                   Function(m) If(m.Index > 0, "_", "") +
                                               m.Groups(1).Value.ToUpper +
                                               m.Groups(2).Value)
    
            ' Display the resulting string.
            Dim line As Integer = 0
            Do
                Dim nChars As Integer = If(line * 80 + 79 <= sbString.Length,
                                        80, sbString.Length - line * 80)
                Console.WriteLine(sbString.Substring(line * 80, nChars))
                line += 1
            Loop While line * 80 < sbString.Length
        End Sub
    End Module
    ' The example displays the following output:
    '    Aaaa_Bbbb_Cccc_Dddd_Eeee_Ffff_Gggg_Hhhh_Iiii_Jjjj_Kkkk_Llll_Mmmm_Nnnn_Oooo_Pppp_
    '    Qqqq_Rrrr_Ssss_Tttt_Uuuu_Vvvv_Wwww_Xxxx_Yyyy_Zzzz
    

Konvertieren des StringBuilder-Objekts in eine Zeichenfolge

Sie müssen das StringBuilder-Objekt in ein String-Objekt konvertieren, bevor Sie die vom StringBuilder-Objekt dargestellte Zeichenfolge an eine Methode mit einem String-Parameter übergeben können oder diese auf der Benutzeroberfläche anzeigen. Sie führen diese Konvertierung durch Aufrufen der StringBuilder.ToString Methode aus. Eine Abbildung finden Sie im vorherigen Beispiel, in dem die ToString Methode zum Konvertieren eines StringBuilder Objekts in eine Zeichenfolge aufgerufen wird, damit es an eine reguläre Ausdrucksmethode übergeben werden kann.