Udostępnij za pośrednictwem


System.Text.StringBuilder, klasa

Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.

Klasa StringBuilder reprezentuje obiekt przypominający ciąg, którego wartość jest modyfikowalnym sekwencją znaków.

StringBuilder a Typ ciągu

Mimo że StringBuilder obie String reprezentują sekwencje znaków, są one implementowane inaczej. String jest niezmiennym typem. Oznacza to, że każda operacja, która wydaje się modyfikować String obiekt, faktycznie tworzy nowy ciąg.

Na przykład wywołanie String.Concat metody w poniższym przykładzie języka C# spowoduje zmianę wartości zmiennej ciągu o nazwie value. W rzeczywistości Concat metoda zwraca value obiekt, który ma inną wartość i adres z value obiektu przekazanego do metody. Należy pamiętać, że przykład musi zostać skompilowany przy użyciu opcji kompilatora /unsafe .

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

W przypadku procedur, które wykonują obszerne manipulowanie ciągami (takie jak aplikacje, które modyfikują ciąg wielokrotnie w pętli), modyfikowanie ciągu wielokrotnie może wymagać znacznej kary za wydajność. Alternatywą jest użycie klasy StringBuilder, która jest modyfikowalnym klasą ciągów. Niezmienność oznacza, że po utworzeniu wystąpienia klasy można go zmodyfikować, dołączając, usuwając, zastępując lub wstawiając znaki. Obiekt StringBuilder utrzymuje bufor, aby pomieścić rozszerzenia do ciągu. Nowe dane są dołączane do buforu, jeśli pomieszczenie jest dostępne; W przeciwnym razie przydzielany jest nowy, większy bufor, dane z oryginalnego buforu są kopiowane do nowego buforu, a nowe dane są następnie dołączane do nowego buforu.

Ważne

StringBuilder Mimo że klasa zazwyczaj zapewnia lepszą wydajność niż String klasa, nie należy automatycznie zastępować String wartością StringBuilder za każdym razem, gdy chcesz manipulować ciągami. Wydajność zależy od rozmiaru ciągu, ilości pamięci do przydzielenia dla nowego ciągu, systemu, na którym jest wykonywany kod, oraz typu operacji. Należy przygotować się do przetestowania kodu, aby określić, czy StringBuilder rzeczywiście oferuje znaczną poprawę wydajności.

Rozważ użycie String klasy w następujących warunkach:

  • Gdy liczba zmian, które kod wprowadzi w ciągu, jest mała. W takich przypadkach StringBuilder może oferować nieznaczne lub brak poprawy wydajności w porównaniu z String.

  • Podczas wykonywania stałej liczby operacji łączenia, szczególnie w przypadku literałów ciągów. W takim przypadku kompilator może połączyć operacje łączenia w jedną operację.

  • Gdy podczas tworzenia ciągu trzeba wykonywać obszerne operacje wyszukiwania. Klasa StringBuilder nie ma metod wyszukiwania, takich jak IndexOf lub StartsWith. Musisz przekonwertować StringBuilder obiekt na String obiekt dla tych operacji i może to uniemożliwić korzystanie z wydajności przy użyciu polecenia StringBuilder. Aby uzyskać więcej informacji, zobacz sekcję Wyszukiwanie tekstu w obiekcie StringBuilder.

Rozważ użycie StringBuilder klasy w następujących warunkach:

  • Jeśli oczekujesz, że kod wprowadzi nieznaną liczbę zmian w ciągu w czasie projektowania (na przykład gdy używasz pętli do łączenia losowej liczby ciągów zawierających dane wejściowe użytkownika).
  • Jeśli oczekujesz, że kod wprowadzi znaczną liczbę zmian w ciągu.

Jak działa StringBuilder

Właściwość StringBuilder.Length wskazuje liczbę znaków, StringBuilder które obecnie zawiera obiekt. Jeśli dodasz znaki do StringBuilder obiektu, jego długość zwiększa się, dopóki nie będzie równa rozmiarowi StringBuilder.Capacity właściwości, która definiuje liczbę znaków, które może zawierać obiekt. Jeśli liczba dodanych znaków powoduje, że długość StringBuilder obiektu przekroczy bieżącą pojemność, zostanie przydzielona nowa pamięć, wartość Capacity właściwości zostanie podwoiona, nowe znaki zostaną dodane do StringBuilder obiektu, a jego Length właściwość zostanie skorygowana. Dodatkowa pamięć dla StringBuilder obiektu jest przydzielana dynamicznie, dopóki nie osiągnie wartości zdefiniowanej StringBuilder.MaxCapacity przez właściwość. Po osiągnięciu maksymalnej pojemności nie można przydzielić dodatkowej pamięci dla StringBuilder obiektu i próbuje dodać znaki lub rozwinąć je poza maksymalną pojemnością ArgumentOutOfRangeException zgłasza wyjątek lub.OutOfMemoryException

W poniższym przykładzie pokazano, jak StringBuilder obiekt przydziela nową pamięć i dynamicznie zwiększa pojemność, gdy ciąg przypisany do obiektu się rozwija. Kod tworzy StringBuilder obiekt, wywołując jego domyślny (bez parametrów) konstruktor. Domyślna pojemność tego obiektu wynosi 16 znaków, a jego maksymalna pojemność wynosi ponad 2 miliardy znaków. Dołączenie ciągu "To jest zdanie". Powoduje utworzenie nowej alokacji pamięci, ponieważ długość ciągu (19 znaków) przekracza domyślną pojemność StringBuilder obiektu. Pojemność obiektu podwoi się do 32 znaków, zostanie dodany nowy ciąg, a długość obiektu wynosi teraz 19 znaków. Następnie kod dołącza ciąg "To jest dodatkowe zdanie". do wartości StringBuilder obiektu 11 razy. Za każdym razem, gdy operacja dołączania powoduje StringBuilder przekroczenie pojemności obiektu, jego istniejąca pojemność zostanie podwoina i Append operacja zakończy się pomyślnie.

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

Alokacja pamięci

Domyślna pojemność StringBuilder obiektu to 16 znaków, a jego domyślna maksymalna pojemność to Int32.MaxValue. Te wartości domyślne są używane w przypadku wywoływania StringBuilder() konstruktorów i StringBuilder(String) .

Można jawnie zdefiniować początkową pojemność StringBuilder obiektu w następujący sposób:

  • Wywołując dowolny z StringBuilder konstruktorów, który zawiera capacity parametr podczas tworzenia obiektu.

  • Jawne przypisanie nowej wartości do właściwości w StringBuilder.Capacity celu rozwinięcia istniejącego StringBuilder obiektu. Należy pamiętać, że właściwość zgłasza wyjątek, jeśli nowa pojemność jest mniejsza niż istniejąca pojemność lub większa niż StringBuilder maksymalna pojemność obiektu.

  • Wywołując metodę StringBuilder.EnsureCapacity z nową pojemnością. Nowa pojemność nie może być większa niż StringBuilder maksymalna pojemność obiektu. Jednak w przeciwieństwie do przypisania do Capacity właściwości nie zgłasza wyjątku, EnsureCapacity jeśli żądana nowa pojemność jest mniejsza niż istniejąca pojemność; w tym przypadku wywołanie metody nie ma wpływu.

Jeśli długość ciągu przypisanego do StringBuilder obiektu w wywołaniu konstruktora przekracza pojemność domyślną lub określoną pojemność, Capacity właściwość jest ustawiona na długość ciągu określonego za pomocą parametru value .

Można jawnie zdefiniować maksymalną pojemność StringBuilder obiektu przez wywołanie konstruktora StringBuilder(Int32, Int32) . Nie można zmienić maksymalnej pojemności, przypisując nową wartość do właściwości, ponieważ jest ona tylko do MaxCapacity odczytu.

Jak pokazano w poprzedniej sekcji, za każdym razem, gdy istniejąca pojemność jest niewystarczająca, zostanie przydzielona dodatkowa pamięć, a pojemność StringBuilder obiektu podwoi się do wartości zdefiniowanej MaxCapacity przez właściwość.

Ogólnie rzecz biorąc, pojemność domyślna i maksymalna pojemność są odpowiednie dla większości aplikacji. Możesz rozważyć ustawienie tych wartości w następujących warunkach:

  • Jeśli ostateczna wielkość StringBuilder obiektu może wzrosnąć zbyt duże, zazwyczaj przekracza kilka megabajtów. W takim przypadku może wystąpić pewna korzyść z wydajności dzięki ustawieniu właściwości początkowej Capacity na znacznie wysoką wartość, aby wyeliminować potrzebę zbyt wielu lokalizacji pamięci.

  • Jeśli kod jest uruchomiony w systemie z ograniczoną ilością pamięci. W takim przypadku warto rozważyć ustawienie MaxCapacity właściwości na mniejszą niż Int32.MaxValue wtedy, gdy kod obsługuje duże ciągi, które mogą spowodować jego wykonanie w środowisku z ograniczeniami pamięci.

Tworzenie wystąpienia obiektu StringBuilder

Utworzenie wystąpienia StringBuilder obiektu przez wywołanie jednego z sześciu przeciążonych konstruktorów klas, które są wymienione w poniższej tabeli. Trzy konstruktory tworzy wystąpienie StringBuilder obiektu, którego wartość jest pustym ciągiem, ale ustawiają jego Capacity wartości i MaxCapacity inaczej. Pozostałe trzy konstruktory definiują StringBuilder obiekt, który ma określoną wartość ciągu i pojemność. Dwa z trzech konstruktorów używają domyślnej maksymalnej pojemności Int32.MaxValue, natomiast trzecia pozwala ustawić maksymalną pojemność.

Konstruktor Wartość ciągu Wydajność Maksymalna pojemność
StringBuilder() String.Empty 16 Int32.MaxValue
StringBuilder(Int32) String.Empty Zdefiniowane przez capacity parametr Int32.MaxValue
StringBuilder(Int32, Int32) String.Empty Zdefiniowane przez capacity parametr Zdefiniowane przez maxCapacity parametr
StringBuilder(String) Zdefiniowane przez value parametr 16 lub value. Length, w zależności od tego, która wartość jest większa Int32.MaxValue
StringBuilder(String, Int32) Zdefiniowane przez value parametr Zdefiniowane przez capacity parametr lub value. Length, w zależności od tego, która wartość jest większa. Int32.MaxValue
StringBuilder(String, Int32, Int32, Int32) Zdefiniowane przez value. Substring(startIndex, length) Zdefiniowane przez capacity parametr lub value. Length, w zależności od tego, która wartość jest większa. Int32.MaxValue

W poniższym przykładzie użyto trzech przeciążeń tych konstruktorów do utworzenia wystąpień StringBuilder obiektów.

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

Wywoływanie metod StringBuilder

Większość metod modyfikujących StringBuilder ciąg w wystąpieniu zwraca odwołanie do tego samego wystąpienia. Dzięki temu można wywoływać StringBuilder metody na dwa sposoby:

  • Możesz wykonać wywołania poszczególnych metod i zignorować wartość zwracaną, jak w poniższym przykładzie.

    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.
    
  • Serię wywołań metod można wykonać w jednej instrukcji. Może to być wygodne, jeśli chcesz napisać pojedynczą instrukcję, która będzie łańcuchem kolejnych operacji. Poniższy przykład konsoliduje trzy wywołania metody z poprzedniego przykładu w jeden wiersz kodu.

    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.
    

Wykonywanie operacji StringBuilder

Metody klasy umożliwiają StringBuilder iterowanie, dodawanie, usuwanie lub modyfikowanie znaków w StringBuilder obiekcie.

Iterowanie znaków StringBuilder

Dostęp do znaków w StringBuilder obiekcie można uzyskać za pomocą StringBuilder.Chars[] właściwości . W języku C# Chars[] jest indeksatorem; w Visual Basic jest to domyślna właściwość StringBuilder klasy. Dzięki temu można ustawić lub pobrać poszczególne znaki tylko przy użyciu indeksu Chars[] bez jawnego odwoływania się do właściwości. Znaki w obiekcie zaczynają się od indeksu StringBuilder 0 (zero) i kontynuuj indeksowanie Length — 1.

Poniższy przykład ilustruje Chars[] właściwość . Dołącza dziesięć losowych liczb do StringBuilder obiektu, a następnie iteruje każdy znak. Jeśli kategoria Unicode znaku to UnicodeCategory.DecimalDigitNumber, zmniejsza liczbę o 1 (lub zmienia liczbę na 9, jeśli jej wartość to 0). W przykładzie wyświetlana jest zawartość StringBuilder obiektu zarówno przed, jak i po zmianie wartości poszczególnych znaków.

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

Użycie indeksowania opartego na znakach z właściwością Chars[] może być bardzo powolne w następujących warunkach:

  • Wystąpienie StringBuilder jest duże (na przykład składa się z kilkudziesiąt tysięcy znaków).
  • Jest StringBuilder "kawałek". Oznacza to, że powtarzające się wywołania metod, takie jak StringBuilder.Append automatycznie rozszerzyły właściwość obiektu StringBuilder.Capacity i przydzieliły do niego nowe fragmenty pamięci.

Wydajność ma poważny wpływ, ponieważ każdy dostęp do znaków przechodzi przez całą połączoną listę fragmentów w celu znalezienia poprawnego buforu do indeksowania.

Uwaga

Nawet w przypadku dużego obiektu "fragmenty" StringBuilder przy użyciu Chars[] właściwości na potrzeby dostępu opartego na indeksie do jednej lub niewielkiej liczby znaków ma niewielki wpływ na wydajność; zazwyczaj jest to operacja O(n). Znaczący wpływ na wydajność występuje podczas iterowania znaków w StringBuilder obiekcie, który jest operacją O(n^2).

Jeśli wystąpią problemy z wydajnością podczas korzystania z indeksowania opartego na znakach z StringBuilder obiektami, możesz użyć dowolnego z następujących obejść:

  • Przekonwertuj StringBuilder wystąpienie na klasę String , wywołując metodę ToString , a następnie uzyskaj dostęp do znaków w ciągu.

  • Skopiuj zawartość istniejącego StringBuilder obiektu do nowego obiektu wstępnie utworzonego StringBuilder . Wydajność poprawia się, ponieważ nowy StringBuilder obiekt nie jest fragmenty. Na przykład:

    // 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)
    
  • Ustaw początkową pojemność StringBuilder obiektu na wartość, która jest w przybliżeniu równa maksymalnemu oczekiwanemu StringBuilder(Int32) rozmiarowi, wywołując konstruktora. Należy pamiętać, że przydziela cały blok pamięci, nawet jeśli StringBuilder rzadko osiąga maksymalną pojemność.

Dodawanie tekstu do obiektu StringBuilder

Klasa StringBuilder zawiera następujące metody rozszerzania zawartości StringBuilder obiektu:

  • Metoda Append dołącza ciąg, podciąg, tablicę znaków, część tablicy znaków, pojedynczy znak powtarzany wiele razy lub ciąg reprezentujący pierwotny typ danych do StringBuilder obiektu.

  • Metoda AppendLine dołącza terminator wiersza lub ciąg wraz z terminatorem StringBuilder wiersza do obiektu.

  • Metoda AppendFormat dołącza do obiektu ciąg formatu złożonego StringBuilder . Reprezentacje ciągów obiektów zawartych w ciągu wynikowym mogą odzwierciedlać konwencje formatowania bieżącej kultury systemu lub określonej kultury.

  • Metoda Insert wstawia ciąg, podciąg, wiele powtórzeń ciągu, tablicę znaków, część tablicy znaków lub reprezentację ciągu pierwotnego typu danych na określonej pozycji w StringBuilder obiekcie. Pozycja jest definiowana przez indeks oparty na zerze.

W poniższym przykładzie użyto Appendmetod , AppendLine, AppendFormati Insert w celu rozwinięcia StringBuilder tekstu obiektu.

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            <

Usuwanie tekstu z obiektu StringBuilder

Klasa StringBuilder zawiera metody, które mogą zmniejszyć rozmiar bieżącego StringBuilder wystąpienia. Metoda Clear usuwa wszystkie znaki i ustawia Length właściwość na zero. Metoda Remove usuwa określoną liczbę znaków rozpoczynających się od określonej pozycji indeksu. Ponadto można usunąć znaki z końca StringBuilder obiektu, ustawiając jego Length właściwość na wartość mniejszą niż długość bieżącego wystąpienia.

Poniższy przykład usuwa część tekstu z StringBuilder obiektu, wyświetla jego wynikową pojemność, maksymalną pojemność i wartości właściwości length, a następnie wywołuje metodę Clear , aby usunąć wszystkie znaki z StringBuilder obiektu.

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

Modyfikowanie tekstu w obiekcie StringBuilder

Metoda StringBuilder.Replace zastępuje wszystkie wystąpienia znaku lub ciągu w całym StringBuilder obiekcie lub w określonym zakresie znaków. W poniższym przykładzie użyto Replace metody , aby zastąpić wszystkie wykrzykniki (!) znakami zapytania (?) w StringBuilder obiekcie.

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?

Wyszukiwanie tekstu w obiekcie StringBuilder

Klasa StringBuilder nie zawiera metod podobnych do String.Containsmetod , String.IndexOfi String.StartsWith dostarczonych przez String klasę, co umożliwia wyszukiwanie obiektu podciągów lub określonego znaku. Określenie obecności lub pozycji znaku początkowego podciągów wymaga przeszukania String wartości przy użyciu metody wyszukiwania ciągów lub metody wyrażenia regularnego. Istnieją cztery sposoby implementowania takich wyszukiwań, jak pokazano w poniższej tabeli.

Technika Plusy Minusy
Wyszukaj wartości ciągu przed dodaniem ich do StringBuilder obiektu. Przydatne do określania, czy podciąg istnieje. Nie można użyć, gdy pozycja indeksu podciągu jest ważna.
Wywołaj ToString i przeszukaj zwrócony String obiekt. Łatwość użycia, jeśli przypiszesz cały tekst do StringBuilder obiektu, a następnie zaczniesz go modyfikować. Uciążliwe wielokrotnie wywoływanie ToString , jeśli musisz wprowadzić modyfikacje przed dodaniu całego tekstu do StringBuilder obiektu.

Pamiętaj, aby pracować od końca StringBuilder tekstu obiektu, jeśli wprowadzasz zmiany.
Użyj właściwości , Chars[] aby sekwencyjnie przeszukiwać zakres znaków. Przydatne, jeśli dotyczy to pojedynczych znaków lub małego podciągu. Kłopotliwe, jeśli liczba znaków do wyszukania jest duża lub jeśli logika wyszukiwania jest złożona.

Skutkuje bardzo niską wydajnością obiektów, które stały się bardzo duże za pomocą powtarzających się wywołań metod.
Przekonwertuj StringBuilderString obiekt na obiekt i przeprowadź modyfikacje obiektu String . Przydatne, jeśli liczba modyfikacji jest mała. Neguje korzyść StringBuilder z wydajności klasy, jeśli liczba modyfikacji jest duża.

Przyjrzyjmy się tym technikom bardziej szczegółowo.

  • Jeśli celem wyszukiwania jest określenie, czy istnieje określony podciąg (czyli jeśli nie interesuje Cię pozycja podciągów), możesz wyszukiwać ciągi przed zapisaniem ich w StringBuilder obiekcie. Poniższy przykład przedstawia jedną z możliwych implementacji. Definiuje klasę StringBuilderFinder , której konstruktor jest przekazywany odwołanie do StringBuilder obiektu i podciąg do znalezienia w ciągu. W tym przypadku przykład próbuje określić, czy zarejestrowane temperatury znajdują się w Fahrenheita lub Celsjuszu, i dodaje odpowiedni tekst wprowadzający na początku StringBuilder obiektu. Generator liczb losowych służy do wybierania tablicy zawierającej dane w stopniach Celsjusza lub stopniach Fahrenheita.

    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
    
  • Wywołaj metodę , StringBuilder.ToString aby przekonwertować StringBuilder obiekt na String obiekt. Ciąg można przeszukiwać przy użyciu metod, takich jak String.LastIndexOf lub String.StartsWith, lub można użyć wyrażeń regularnych i Regex klasy do wyszukiwania wzorców. Ponieważ oba StringBuilder obiekty i String używają kodowania UTF-16 do przechowywania znaków, pozycje indeksu znaków, podciągów i dopasowania wyrażeń regularnych są takie same w obu obiektach. Dzięki temu można używać StringBuilder metod do wprowadzania zmian w tej samej pozycji, w której ten tekst znajduje się w String obiekcie.

    Uwaga

    W przypadku przyjęcia tego podejścia należy pracować od końca StringBuilder obiektu do jego początku, aby nie trzeba było wielokrotnie konwertować StringBuilder obiektu na ciąg.

    To podejście pokazano w poniższym przykładzie. Przechowuje cztery wystąpienia każdej litery alfabetu angielskiego w StringBuilder obiekcie. Następnie konwertuje tekst na String obiekt i używa wyrażenia regularnego do identyfikowania pozycji początkowej każdej sekwencji czterech znaków. Na koniec dodaje podkreślenie przed każdą czteroznakową sekwencją z wyjątkiem pierwszej sekwencji i konwertuje pierwszy znak sekwencji na wielkie litery.

    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
    
  • Użyj właściwości , StringBuilder.Chars[] aby sekwencyjnie przeszukiwać zakres znaków w StringBuilder obiekcie. Takie podejście może nie być praktyczne, jeśli liczba wyszukiwanych znaków jest duża lub logika wyszukiwania jest szczególnie złożona. Aby uzyskać wpływ na wydajność dostępu opartego na indeksie znaków dla bardzo dużych, fragmentowanych StringBuilder obiektów, zobacz dokumentację StringBuilder.Chars[] właściwości .

    Poniższy przykład jest identyczny w funkcjonalności poprzedniego przykładu, ale różni się implementacją. Używa Chars[] właściwości do wykrywania, kiedy wartość znaku uległa zmianie, wstawia podkreślenie w tej pozycji i konwertuje pierwszy znak w nowej sekwencji na wielkie litery.

    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
    
  • Zapisz cały niezmodyfikowany tekst w StringBuilder obiekcie, wywołaj StringBuilder.ToString metodę , aby przekonwertować StringBuilder obiekt na String obiekt i wykonać modyfikacje obiektu String . Możesz użyć tej metody, jeśli masz tylko kilka modyfikacji; w przeciwnym razie koszt pracy z niezmienialnymi ciągami może negować korzyści z wydajności korzystania z StringBuilder obiektu.

    Poniższy przykład jest identyczny w funkcjonalności z poprzednimi dwoma przykładami, ale różni się implementacją. StringBuilder Tworzy obiekt, konwertuje go na String obiekt, a następnie używa wyrażenia regularnego do wykonywania wszystkich pozostałych modyfikacji w ciągu. Metoda Regex.Replace(String, String, MatchEvaluator) używa wyrażenia lambda do wykonania zamiany na każdym dopasowaniu.

    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
    

Konwertowanie obiektu StringBuilder na ciąg

Należy przekonwertować StringBuilder obiekt na String obiekt, aby można było przekazać ciąg reprezentowany przez StringBuilder obiekt do metody, która ma String parametr lub wyświetlić go w interfejsie użytkownika. Ta konwersja jest wykonywana przez wywołanie StringBuilder.ToString metody . Aby zapoznać się z ilustracją, zobacz poprzedni przykład, który wywołuje ToString metodę w celu przekonwertowania StringBuilder obiektu na ciąg, aby można było przekazać go do metody wyrażenia regularnego.