Classe System.Text.StringBuilder

Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.

La StringBuilder classe rappresenta un oggetto simile a una stringa il cui valore è una sequenza modificabile di caratteri.

StringBuilder e tipo String

Sebbene StringBuilder e String rappresentino entrambe le sequenze di caratteri, vengono implementate in modo diverso. String è un tipo non modificabile. Ovvero, ogni operazione che sembra modificare un String oggetto crea effettivamente una nuova stringa.

Ad esempio, la chiamata al String.Concat metodo nell'esempio C# seguente sembra modificare il valore di una variabile stringa denominata value. Il metodo restituisce Concat infatti un value oggetto con un valore e un indirizzo diversi dall'oggetto value passato al metodo . Si noti che l'esempio deve essere compilato usando l'opzione del /unsafe compilatore.

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

Per le routine che eseguono una manipolazione estesa delle stringhe (ad esempio le app che modificano una stringa più volte in un ciclo), la modifica di una stringa ripetutamente può comportare una riduzione significativa delle prestazioni. L'alternativa consiste nell'usare StringBuilder, ovvero una classe stringa modificabile. La mutabilità significa che una volta creata un'istanza della classe, può essere modificata aggiungendo, rimuovendo, sostituendo o inserendo caratteri. Un StringBuilder oggetto mantiene un buffer per contenere le espansioni alla stringa. I nuovi dati vengono aggiunti al buffer se la stanza è disponibile; in caso contrario, viene allocato un nuovo buffer di dimensioni maggiori, i dati del buffer originale vengono copiati nel nuovo buffer e i nuovi dati vengono quindi accodati al nuovo buffer.

Importante

Anche se la StringBuilder classe offre in genere prestazioni migliori rispetto alla String classe , non è consigliabile sostituire String automaticamente con StringBuilder ogni volta che si desidera modificare le stringhe. Le prestazioni dipendono dalle dimensioni della stringa, dalla quantità di memoria da allocare per la nuova stringa, dal sistema in cui viene eseguito il codice e dal tipo di operazione. È necessario essere pronti a testare il codice per determinare se StringBuilder effettivamente offre un miglioramento significativo delle prestazioni.

Prendere in considerazione l'uso della String classe in queste condizioni:

  • Quando il numero di modifiche apportate dal codice a una stringa è ridotto. In questi casi, StringBuilder potrebbe offrire un miglioramento trascurabile o nessun miglioramento delle prestazioni rispetto Stringa .

  • Quando si esegue un numero fisso di operazioni di concatenazione, in particolare con valori letterali stringa. In questo caso, il compilatore potrebbe combinare le operazioni di concatenazione in una singola operazione.

  • Quando è necessario eseguire operazioni di ricerca estese durante la compilazione della stringa. La StringBuilder classe non dispone di metodi di ricerca come IndexOf o StartsWith. Sarà necessario convertire l'oggetto StringBuilder in un oggetto String per queste operazioni e ciò può negare il vantaggio delle prestazioni dall'uso StringBuilderdi . Per altre informazioni, vedere la sezione Cercare il testo in un oggetto StringBuilder.

Prendere in considerazione l'uso della StringBuilder classe in queste condizioni:

  • Quando si prevede che il codice esemplivi un numero sconosciuto di modifiche a una stringa in fase di progettazione, ad esempio quando si usa un ciclo per concatenare un numero casuale di stringhe che contengono l'input dell'utente.
  • Quando si prevede che il codice apporta un numero significativo di modifiche a una stringa.

Funzionamento di StringBuilder

La StringBuilder.Length proprietà indica il numero di caratteri attualmente contenuti nell'oggetto StringBuilder . Se si aggiungono caratteri all'oggetto StringBuilder , la lunghezza aumenta fino a quando non è uguale alla dimensione della StringBuilder.Capacity proprietà, che definisce il numero di caratteri che l'oggetto può contenere. Se il numero di caratteri aggiunti determina il superamento della capacità corrente dell'oggetto StringBuilder , viene allocata una nuova memoria, il valore della Capacity proprietà viene raddoppiato, i nuovi caratteri vengono aggiunti all'oggetto StringBuilder e la relativa Length proprietà viene modificata. La memoria aggiuntiva per l'oggetto StringBuilder viene allocata dinamicamente fino a raggiungere il valore definito dalla StringBuilder.MaxCapacity proprietà . Quando viene raggiunta la capacità massima, non è possibile allocare ulteriore memoria per l'oggetto StringBuilder e tentare di aggiungere caratteri o espanderlo oltre la capacità massima genera un'eccezione OutOfMemoryExceptionArgumentOutOfRangeException o .

Nell'esempio seguente viene illustrato come un StringBuilder oggetto alloca nuova memoria e ne aumenta la capacità in modo dinamico man mano che la stringa assegnata all'oggetto si espande. Il codice crea un StringBuilder oggetto chiamando il costruttore predefinito (senza parametri). La capacità predefinita di questo oggetto è di 16 caratteri e la capacità massima è superiore a 2 miliardi di caratteri. L'aggiunta della stringa "Questa è una frase." comporta una nuova allocazione di memoria perché la lunghezza della stringa (19 caratteri) supera la capacità predefinita dell'oggetto StringBuilder . La capacità dell'oggetto raddoppia a 32 caratteri, viene aggiunta la nuova stringa e la lunghezza dell'oggetto è ora uguale a 19 caratteri. Il codice aggiunge quindi la stringa "Questa è una frase aggiuntiva". Al valore dell'oggetto StringBuilder 11 volte. Ogni volta che l'operazione di accodamento determina il superamento della capacità dell'oggetto StringBuilder , la capacità esistente viene raddoppiata e l'operazione Append ha esito positivo.

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

Allocazione della memoria

La capacità predefinita di un StringBuilder oggetto è di 16 caratteri e la capacità massima predefinita è Int32.MaxValue. Questi valori predefiniti vengono usati se si chiamano i StringBuilder() costruttori e StringBuilder(String) .

È possibile definire in modo esplicito la capacità iniziale di un StringBuilder oggetto nei modi seguenti:

  • Chiamando uno dei StringBuilder costruttori che include un capacity parametro quando si crea l'oggetto .

  • Assegnando in modo esplicito un nuovo valore alla StringBuilder.Capacity proprietà per espandere un oggetto esistente StringBuilder . Si noti che la proprietà genera un'eccezione se la nuova capacità è minore della capacità esistente o maggiore StringBuilder della capacità massima dell'oggetto.

  • Chiamando il StringBuilder.EnsureCapacity metodo con la nuova capacità. La nuova capacità non deve essere maggiore della StringBuilder capacità massima dell'oggetto. Tuttavia, a differenza di un'assegnazione alla Capacity proprietà, EnsureCapacity non genera un'eccezione se la nuova capacità desiderata è minore della capacità esistente. In questo caso, la chiamata al metodo non ha alcun effetto.

Se la lunghezza della stringa assegnata all'oggetto StringBuilder nella chiamata al costruttore supera la capacità predefinita o la capacità specificata, la Capacity proprietà viene impostata sulla lunghezza della stringa specificata con il value parametro .

È possibile definire in modo esplicito la capacità massima di un StringBuilder oggetto chiamando il StringBuilder(Int32, Int32) costruttore . Non è possibile modificare la capacità massima assegnando un nuovo valore alla MaxCapacity proprietà, perché è di sola lettura.

Come illustrato nella sezione precedente, ogni volta che la capacità esistente è inadeguata, viene allocata memoria aggiuntiva e la capacità di un StringBuilder oggetto raddoppia fino al valore definito dalla MaxCapacity proprietà .

In generale, la capacità predefinita e la capacità massima sono adeguate per la maggior parte delle app. È possibile impostare questi valori nelle condizioni seguenti:

  • Se è probabile che la dimensione finale dell'oggetto StringBuilder cresca in modo eccessivamente elevato, in genere in eccesso di diversi megabyte. In questo caso, potrebbe esserci un certo vantaggio dalle prestazioni dell'impostazione della proprietà iniziale Capacity su un valore significativamente elevato per eliminare la necessità di troppe riallocazioni di memoria.

  • Se il codice è in esecuzione in un sistema con memoria limitata. In questo caso, è consigliabile impostare la MaxCapacity proprietà su minore di Int32.MaxValue se il codice gestisce stringhe di grandi dimensioni che potrebbero causare l'esecuzione in un ambiente con vincoli di memoria.

Creare un'istanza di un oggetto StringBuilder

Per creare un'istanza di un StringBuilder oggetto, chiamare uno dei sei costruttori di classi di overload elencati nella tabella seguente. Tre dei costruttori creano un'istanza di un StringBuilder oggetto il cui valore è una stringa vuota, ma imposta i relativi Capacity valori e MaxCapacity in modo diverso. I tre costruttori rimanenti definiscono un StringBuilder oggetto con un valore stringa e una capacità specifici. Due dei tre costruttori usano la capacità massima predefinita di Int32.MaxValue, mentre la terza consente di impostare la capacità massima.

Costruttore Valore stringa Capacità Capacità massima
StringBuilder() String.Empty 16 Int32.MaxValue
StringBuilder(Int32) String.Empty Definito dal capacity parametro Int32.MaxValue
StringBuilder(Int32, Int32) String.Empty Definito dal capacity parametro Definito dal maxCapacity parametro
StringBuilder(String) Definito dal value parametro 16 o value. Length, indipendentemente dal fatto che sia maggiore Int32.MaxValue
StringBuilder(String, Int32) Definito dal value parametro Definito dal capacity parametro o value. Length, indipendentemente dal fatto che sia maggiore. Int32.MaxValue
StringBuilder(String, Int32, Int32, Int32) definito da value. Substring(startIndex, length) Definito dal capacity parametro o value. Length, indipendentemente dal fatto che sia maggiore. Int32.MaxValue

Nell'esempio seguente vengono usati tre di questi overload del costruttore per creare un'istanza di StringBuilder oggetti.

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

Chiamare i metodi StringBuilder

La maggior parte dei metodi che modificano la stringa in un'istanza StringBuilder restituisce un riferimento alla stessa istanza. In questo modo è possibile chiamare StringBuilder i metodi in due modi:

  • È possibile effettuare chiamate a singoli metodi e ignorare il valore restituito, come illustrato nell'esempio seguente.

    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.
    
  • È possibile effettuare una serie di chiamate al metodo in una singola istruzione. Ciò può essere utile se si vuole scrivere una singola istruzione che concatena le operazioni successive. Nell'esempio seguente vengono consolidate tre chiamate al metodo dell'esempio precedente in una singola riga di codice.

    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.
    

Eseguire operazioni di StringBuilder

È possibile utilizzare i metodi della StringBuilder classe per scorrere, aggiungere, eliminare o modificare caratteri in un StringBuilder oggetto .

Iterate StringBuilder characters (Iterate StringBuilder characters)

È possibile accedere ai caratteri in un StringBuilder oggetto usando la StringBuilder.Chars[] proprietà . In C# Chars[] è un indicizzatore. In Visual Basic è la proprietà predefinita della StringBuilder classe . In questo modo è possibile impostare o recuperare singoli caratteri usando solo l'indice, senza fare riferimento in modo esplicito alla Chars[] proprietà . I caratteri in un StringBuilder oggetto iniziano in corrispondenza dell'indice 0 (zero) e continuano a indicizzare Length - 1.

Nell'esempio seguente viene illustrata la Chars[] proprietà . Aggiunge dieci numeri casuali a un StringBuilder oggetto e quindi esegue l'iterazione di ogni carattere. Se la categoria Unicode del carattere è UnicodeCategory.DecimalDigitNumber, diminuisce il numero di 1 (o imposta il numero su 9 se il valore è 0). Nell'esempio viene visualizzato il contenuto dell'oggetto StringBuilder sia prima che dopo la modifica dei valori dei singoli caratteri.

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

L'uso dell'indicizzazione basata sui caratteri con la proprietà Chars[] può essere lentissimo nelle condizioni seguenti:

  • L'istanza StringBuilder è di grandi dimensioni (ad esempio, è costituita da diverse decine di migliaia di caratteri).
  • è StringBuilder "in blocchi". Ovvero, le chiamate ripetute ai metodi, ad StringBuilder.Append esempio, hanno espanso automaticamente la proprietà dell'oggetto StringBuilder.Capacity e allocato nuovi blocchi di memoria.

L'impatto sulle prestazioni è notevole poiché ogni accesso ai caratteri scorre l'intero elenco di blocchi collegato per trovare il buffer corretto in cui eseguire l'indicizzazione.

Nota

Anche per un oggetto "in blocchi" StringBuilder di grandi dimensioni, l'uso della Chars[] proprietà per l'accesso basato su indice a uno o un numero ridotto di caratteri ha un impatto trascurabile sulle prestazioni. In genere, si tratta di un'operazione O(n). L'impatto significativo sulle prestazioni si verifica durante l'iterazione dei caratteri nell'oggetto StringBuilder, che è un'operazione O(n^2).

Se si verificano problemi di prestazioni quando si usa l'indicizzazione basata su caratteri con gli oggetti StringBuilder, è possibile adottare una delle seguenti soluzioni alternative:

  • Convertire l'istanza StringBuilder in un String chiamando il metodo ToString, quindi accedere ai caratteri nella stringa.

  • Copiare il contenuto dell'oggetto StringBuilder esistente in un nuovo oggetto StringBuilder con dimensioni preimpostate. Le prestazioni migliorano perché il nuovo oggetto StringBuilder non è pesante. Ad esempio:

    // 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)
    
  • Impostare la capacità iniziale dell'oggetto StringBuilder su un valore approssimativamente uguale alle dimensioni massime previste chiamando il costruttore StringBuilder(Int32). Si noti che in questo modo viene allocato l'intero di memoria anche se StringBuilder raramente raggiunge la capacità massima.

Aggiungere testo a un oggetto StringBuilder

La StringBuilder classe include i metodi seguenti per espandere il contenuto di un StringBuilder oggetto :

  • Il Append metodo aggiunge più volte una stringa, una sottostringa, una matrice di caratteri, una parte di una matrice di caratteri, un singolo carattere ripetuto più volte o la rappresentazione di stringa di un tipo di dati primitivo a un StringBuilder oggetto .

  • Il AppendLine metodo aggiunge un terminatore di riga o una stringa insieme a un terminatore di riga a un StringBuilder oggetto .

  • Il AppendFormat metodo aggiunge una stringa di formato composita a un StringBuilder oggetto . Le rappresentazioni di stringa degli oggetti inclusi nella stringa di risultato possono riflettere le convenzioni di formattazione delle impostazioni cultura di sistema correnti o delle impostazioni cultura specificate.

  • Il Insert metodo inserisce una stringa, una sottostringa, più ripetizioni di una stringa, una matrice di caratteri, una parte di una matrice di caratteri o la rappresentazione di stringa di un tipo di dati primitivo in una posizione specificata nell'oggetto StringBuilder . La posizione è definita da un indice in base zero.

Nell'esempio seguente vengono utilizzati i Appendmetodi , AppendLineAppendFormat, e Insert per espandere il testo di un StringBuilder oggetto .

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            <

Eliminare testo da un oggetto StringBuilder

La StringBuilder classe include metodi che possono ridurre le dimensioni dell'istanza corrente StringBuilder . Il Clear metodo rimuove tutti i caratteri e imposta la Length proprietà su zero. Il Remove metodo elimina un numero specificato di caratteri a partire da una determinata posizione di indice. Inoltre, è possibile rimuovere caratteri dalla fine di un StringBuilder oggetto impostando la relativa Length proprietà su un valore minore della lunghezza dell'istanza corrente.

Nell'esempio seguente viene rimosso parte del testo da un StringBuilder oggetto , viene visualizzata la capacità risultante, la capacità massima e i valori delle proprietà length e quindi viene chiamato il Clear metodo per rimuovere tutti i caratteri dall'oggetto StringBuilder .

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

Modificare il testo in un oggetto StringBuilder

Il StringBuilder.Replace metodo sostituisce tutte le occorrenze di un carattere o di una stringa nell'intero StringBuilder oggetto o in un intervallo di caratteri specifico. Nell'esempio seguente viene utilizzato il Replace metodo per sostituire tutti i punti esclamativi (!) con punti interrogativi (?) nell'oggetto StringBuilder .

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?

Cercare il testo in un oggetto StringBuilder

La StringBuilder classe non include metodi simili ai String.Containsmetodi , String.IndexOfe String.StartsWith forniti dalla String classe , che consentono di cercare un carattere specifico o una sottostringa nell'oggetto. Per determinare la presenza o la posizione iniziale del carattere di una sottostringa, è necessario cercare un String valore usando un metodo di ricerca di stringhe o un metodo di espressione regolare. Esistono quattro modi per implementare tali ricerche, come illustrato nella tabella seguente.

Tecnica Vantaggi Svantaggi
Cercare i valori stringa prima di aggiungerli all'oggetto StringBuilder . Utile per determinare se esiste una sottostringa. Non può essere utilizzato quando la posizione di indice di una sottostringa è importante.
Chiamare ToString e cercare l'oggetto restituito String . Facile da usare se si assegna tutto il testo a un StringBuilder oggetto e quindi iniziare a modificarlo. Complessa da chiamare ToString ripetutamente se è necessario apportare modifiche prima che tutto il testo venga aggiunto all'oggetto StringBuilder .

È necessario ricordare di lavorare dalla fine del StringBuilder testo dell'oggetto se si apportano modifiche.
Utilizzare la Chars[] proprietà per cercare in sequenza un intervallo di caratteri. Utile se si è interessati a singoli caratteri o a una piccola sottostringa. Complesso se il numero di caratteri da cercare è elevato o se la logica di ricerca è complessa.

Si ottengono prestazioni molto scarse per gli oggetti che sono cresciuti molto grandi tramite chiamate di metodo ripetute.
Convertire l'oggetto StringBuilder in un String oggetto ed eseguire modifiche sull'oggetto String . Utile se il numero di modifiche è ridotto. Nega il vantaggio delle prestazioni della StringBuilder classe se il numero di modifiche è elevato.

Esaminiamo queste tecniche in modo più dettagliato.

  • Se l'obiettivo della ricerca è determinare se esiste una particolare sottostringa, ovvero se non si è interessati alla posizione della sottostringa, è possibile cercare le stringhe prima di archiviarle nell'oggetto StringBuilder . Nell'esempio seguente viene fornita una possibile implementazione. Definisce una StringBuilderFinder classe il cui costruttore viene passato a un riferimento a un StringBuilder oggetto e alla sottostringa da trovare nella stringa. In questo caso, l'esempio tenta di determinare se le temperature registrate sono in Fahrenheit o Celsius e aggiunge il testo introduttivo appropriato all'inizio dell'oggetto StringBuilder . Un generatore di numeri casuali viene usato per selezionare una matrice che contiene dati in gradi Celsius o gradi Fahrenheit.

    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
    
  • Chiamare il StringBuilder.ToString metodo per convertire l'oggetto StringBuilder in un String oggetto . È possibile eseguire ricerche nella stringa usando metodi come String.LastIndexOf o String.StartsWithoppure è possibile usare espressioni regolari e la Regex classe per cercare i criteri. Poiché entrambi gli StringBuilder oggetti e String usano la codifica UTF-16 per archiviare i caratteri, le posizioni di indice dei caratteri, le sottostringhe e le corrispondenze di espressioni regolari sono uguali in entrambi gli oggetti. In questo modo è possibile utilizzare StringBuilder i metodi per apportare modifiche nella stessa posizione in cui il testo viene trovato nell'oggetto String .

    Nota

    Se si adotta questo approccio, è necessario lavorare dalla fine dell'oggetto all'inizio StringBuilder in modo che non sia necessario convertire ripetutamente l'oggetto StringBuilder in una stringa.

    Questo approccio viene illustrato nell'esempio seguente: Archivia quattro occorrenze di ogni lettera dell'alfabeto inglese in un StringBuilder oggetto . Converte quindi il testo in un String oggetto e usa un'espressione regolare per identificare la posizione iniziale di ogni sequenza di quattro caratteri. Infine, aggiunge un carattere di sottolineatura prima di ogni sequenza di quattro caratteri ad eccezione della prima sequenza e converte il primo carattere della sequenza in maiuscolo.

    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
    
  • Utilizzare la StringBuilder.Chars[] proprietà per cercare in sequenza un intervallo di caratteri in un StringBuilder oggetto . Questo approccio potrebbe non essere pratico se il numero di caratteri da cercare è elevato o la logica di ricerca è particolarmente complessa. Per le implicazioni sulle prestazioni dell'accesso in base all'indice di caratteri per oggetti molto grandi e in blocchi StringBuilder , vedere la documentazione per la StringBuilder.Chars[] proprietà .

    L'esempio seguente è identico alla funzionalità dell'esempio precedente, ma differisce nell'implementazione. Usa la Chars[] proprietà per rilevare quando un valore di carattere è stato modificato, inserisce un carattere di sottolineatura in tale posizione e converte il primo carattere nella nuova sequenza in maiuscolo.

    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
    
  • Archiviare tutto il testo non modificato nell'oggetto StringBuilder , chiamare il StringBuilder.ToString metodo per convertire l'oggetto StringBuilder in un String oggetto ed eseguire le modifiche sull'oggetto String . È possibile usare questo approccio se sono presenti solo alcune modifiche; in caso contrario, il costo di utilizzo di stringhe non modificabili può negare i vantaggi delle prestazioni dell'uso di un StringBuilder oggetto .

    L'esempio seguente è identico alle funzionalità dei due esempi precedenti, ma differisce nell'implementazione. Crea un StringBuilder oggetto, lo converte in un String oggetto e quindi usa un'espressione regolare per eseguire tutte le modifiche rimanenti sulla stringa. Il Regex.Replace(String, String, MatchEvaluator) metodo usa un'espressione lambda per eseguire la sostituzione in ogni corrispondenza.

    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
    

Convertire l'oggetto StringBuilder in una stringa

È necessario convertire l'oggetto StringBuilder in un oggetto String prima di poter passare la stringa rappresentata dall'oggetto StringBuilder a un metodo che contiene un parametro String o per visualizzarlo nell'interfaccia utente. Per eseguire questa conversione, chiamare il StringBuilder.ToString metodo . Per un'illustrazione, vedere l'esempio precedente, che chiama il ToString metodo per convertire un StringBuilder oggetto in una stringa in modo che possa essere passato a un metodo di espressione regolare.