System.Text.StringBuilder 類別
本文提供此 API 參考文件的補充備註。
類別 StringBuilder 代表類似字串的物件,其值為可變動的字元序列。
StringBuilder 與 String 類型
雖然 StringBuilder 和 String 都代表字元序列,但實作方式不同。 String 是不可變的類型。 也就是說,每個看似修改 String 對象的作業實際上都會建立新的字串。
例如,下列 C# 範例中方法的 String.Concat 呼叫似乎會變更名為 value
的字串變數值。 事實上, Concat 方法會 value
傳回物件,該對象與傳遞至 方法的物件具有不同的值和位址 value
。 請注意,必須使用編譯程式選項編譯 /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
對於執行大量字串操作的例程(例如在迴圈中多次修改字串的應用程式),重複修改字串可能會造成顯著的效能損失。 替代方法是使用 StringBuilder,這是可變動的字串類別。 可變性表示一旦建立 類別的實例,就可以藉由附加、移除、取代或插入字元來修改它。
重要
雖然 類別 StringBuilder 通常提供比 String 類別更好的效能,但每當您想要操作字串時,您就不應該自動取代 String StringBuilder 。 效能取決於字串大小、要配置給新字串的記憶體數量、程式代碼執行所在的系統,以及作業類型。 您應該準備好測試程序代碼,以判斷是否 StringBuilder 實際提供顯著的效能改善。
請考慮在這些情況下使用 類別 String :
- 當程式代碼對字串所做的變更數目很小時。 在這些情況下, StringBuilder 可能會對 提供微不足道或沒有效能改善 String。
- 當您執行固定數目的串連作業時,特別是字串常值。 在此情況下,編譯程式可能會將串連作業合併成單一作業。
- 當您在建置字串時必須執行廣泛的搜尋作業時。 類別 StringBuilder 缺少 搜尋方法,例如
IndexOf
或StartsWith
。 您必須將 StringBuilder 對象 String 轉換成這些作業的 ,這可以否定使用 StringBuilder的效能效益。 如需詳細資訊,請參閱 在 StringBuilder 物件 中搜尋文字一節。
請考慮在這些情況下使用 類別 StringBuilder :
- 當您預期程式代碼在設計時間對字串進行未知數目的變更時(例如,當您使用迴圈串連包含使用者輸入的隨機字串時)。
- 當您預期程式代碼對字串進行大量變更時。
StringBuilder 的運作方式
屬性 StringBuilder.Length 表示物件目前包含的字元 StringBuilder 數。 如果您將字元新增至 StringBuilder 物件,其長度會增加,直到它等於 屬性的大小 StringBuilder.Capacity ,這會定義物件可包含的字元數。 如果新增的字元數導致對象的長度 StringBuilder 超過其目前容量,則會配置新的記憶體、將屬性的值 Capacity 加倍、將新字元新增至 StringBuilder 物件,並調整其 Length 屬性。 對象的額外記憶體 StringBuilder 會動態配置,直到它到達 屬性所 StringBuilder.MaxCapacity 定義的值為止。 達到容量上限時,無法為 StringBuilder 物件配置任何進一步的記憶體,並嘗試新增字元或將其擴充到超出最大容量時,會擲回 ArgumentOutOfRangeException 或 OutOfMemoryException 例外狀況。
下列範例說明物件如何 StringBuilder 配置新的記憶體,並在指派給物件的字串展開時動態增加其容量。 程式代碼會 StringBuilder 藉由呼叫其預設 (無參數) 建構函式來建立 物件。 此物件的預設容量為 16 個字元,其最大容量超過 20 億個字元。 附加字串 「This is a sentence」。。會導致新的記憶體配置,因為字串長度 (19 個字元) 超過物件的預設容量 StringBuilder 。 物件的容量會加倍至 32 個字元、加入新的字串,而且對象的長度現在等於 19 個字元。 然後,程式代碼會將字串 「這是額外的句子」附加至物件 11 次的值 StringBuilder 。 每當附加作業造成對象的長度 StringBuilder 超過其容量時,其現有的容量就會加倍,而且 Append 作業會成功。
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
記憶體配置
物件的預設容量 StringBuilder 為 16 個字元,其預設容量上限為 Int32.MaxValue。 如果您呼叫 和 StringBuilder(String) 建構函式,StringBuilder()則會使用這些預設值。
您可以透過下列方式明確定義物件的初始容量 StringBuilder :
- 當您建立 物件時,呼叫包含
capacity
參數的任何StringBuilder建構函式。 - 藉由將新的值明確指派給 StringBuilder.Capacity 屬性,以展開現有的 StringBuilder 物件。 (如果新容量小於現有容量或大於 StringBuilder 物件的最大容量,則 屬性會擲回例外狀況。
- 使用新的容量呼叫 StringBuilder.EnsureCapacity 方法。 新的容量不得大於 StringBuilder 物件的最大容量。 不過,與屬性指派 Capacity 不同的是,如果所需的新容量小於現有的容量, EnsureCapacity 則不會擲回例外狀況。 在此情況下,方法呼叫沒有任何作用。
如果指派給 StringBuilder 建構函式呼叫中物件之字串的長度超過預設容量或指定的容量,屬性 Capacity 就會設定為使用 value
參數指定的字串長度。
您可以藉由呼叫 StringBuilder(Int32, Int32) 建構函式,明確定義物件的最大容量StringBuilder。 您無法藉由將新值指派給 MaxCapacity 屬性來變更最大容量,因為它是只讀的。
如上一節所示,每當現有的容量不足時,就會配置額外的記憶體,而物件的容量 StringBuilder 會加倍至 屬性所定義的 MaxCapacity 值。
一般而言,預設容量和容量上限適用於大部分的應用程式。 您可能會考慮在下列情況下設定這些值:
- 如果對象的最終大小 StringBuilder 可能會成長得非常大,通常超過數 MB。 在此情況下,將初始 Capacity 屬性設定為高值,以消除太多記憶體重新配置的需求,可能會有一些效能優點。
- 如果您的程式代碼是在記憶體有限的系統上執行。 在此情況下,您可能會考慮將 屬性設定 MaxCapacity 為小於 Int32.MaxValue 您的程式代碼處理可能導致它在記憶體限制環境中執行的大型字串。
具現化 StringBuilder 物件
您可以藉由呼叫其六個 StringBuilder 多載類別建構函式之一來具現化 物件,如下表所列。 其中三個 StringBuilder 建構函式會具現化其值為空字串的物件,但以不同的方式設定其 Capacity 和 MaxCapacity 值。 其餘三個 StringBuilder 建構函式會定義具有特定字串值和容量的物件。 三個建構函式中的兩個會使用 的預設最大容量 Int32.MaxValue,而第三個建構函式則可讓您設定最大容量。
建構函式 | [字串值] | 容量 | 容量上限 |
---|---|---|---|
StringBuilder() | String.Empty | 16 | Int32.MaxValue |
StringBuilder(Int32) | String.Empty | 由 capacity 參數定義 |
Int32.MaxValue |
StringBuilder(Int32, Int32) | String.Empty | 由 capacity 參數定義 |
由 maxCapacity 參數定義 |
StringBuilder(String) | 由 value 參數定義 |
16 或 value 。 Length,無論哪一個更大 |
Int32.MaxValue |
StringBuilder(String, Int32) | 由 value 參數定義 |
由 capacity 參數或 value 所定義。 Length,無論哪一個更大。 |
Int32.MaxValue |
StringBuilder(String, Int32, Int32, Int32) | 由 value 定義。 Substring(startIndex , length ) |
由 capacity 參數或 value 所定義。 Length,無論哪一個更大。 |
Int32.MaxValue |
下列範例會使用這些建構函式多載的三個來具現化 StringBuilder 物件。
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
呼叫 StringBuilder 方法
修改 實例中 StringBuilder 字串的大部分方法都會傳回該相同實例的參考。 這可讓您以兩種方式呼叫 StringBuilder 方法:
您可以進行個別方法呼叫並忽略傳回值,如下列範例所示。
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.
您可以在單一語句中進行一系列的方法呼叫。 如果您想要撰寫鏈結後續作業的單一語句,這很方便。 下列範例會將前一個範例中的三個方法呼叫合併成單行程序代碼。
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.
執行 StringBuilder 作業
您可以使用 類別的方法 StringBuilder 來反覆運算、新增、刪除或修改物件中的 StringBuilder 字元。
反覆運算 StringBuilder 字元
您可以使用 屬性來存取物件StringBuilder.Chars[]中的StringBuilder字元。 在 C# 中, Chars[] 是索引器;在 Visual Basic 中,它是 類別的預設屬性 StringBuilder 。 這可讓您只使用其索引來設定或擷取個別字元,而不明確參考 Chars[] 屬性。 物件中的 StringBuilder 字元從索引 0 開始(零),並繼續編製索引 Length - 1。
下列範例說明 Chars[] 屬性。 它會將十個 StringBuilder 隨機數附加至 物件,然後逐一查看每個字元。 如果字元的 Unicode 類別是 UnicodeCategory.DecimalDigitNumber,則會將數位減少 1(如果數位值為 0,則數位會變更為 9)。 此範例會顯示變更個別字元值前後對象的內容 StringBuilder 。
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
在下列狀況下,搭配使用以字元為主的索引與 Chars[] 屬性可能極為緩慢:
- StringBuilder 執行個體很大 (例如,它包含幾萬個字元)。
- StringBuilder是「區塊」。也就是說,這類方法StringBuilder.Append的重複呼叫會自動擴充對象的 StringBuilder.Capacity 屬性,並將新的記憶體區塊配置給它。
由於每個字元的存取會行經整個連結的區塊清單來尋找要編入索引的正確緩衝區,因此會嚴重影響效能。
注意
即使是大型的「區塊」 StringBuilder 物件,使用 Chars[] 屬性進行索引型存取一或少數位符也會對效能造成微不足道的影響;一般而言,它是 O(n) 作業。 逐一查看 StringBuilder 物件中的字元時,就會發生顯著的效能影響,這是 O(n^2) 作業。
如果在 StringBuilder 物件中使用以字元為主的索引時遇到效能問題,您可以使用下列任一因應措施:
藉由呼叫 ToString 方法將 StringBuilder 執行個體轉換為 String,然後存取字串中的字元。
將現有 StringBuilder 物件的內容複製到預留大小的新 StringBuilder 物件。 因為新的 StringBuilder 物件不是塊狀,所以會改善效能。 例如:
// 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)
藉由呼叫 StringBuilder(Int32) 建構函式,將 StringBuilder 物件的初始容量設定為大約等於其預期大小上限的值。 請注意,即使 StringBuilder 很少達到其最大容量,這也會配置整個記憶體區塊。
將文字新增至 StringBuilder 物件
類別 StringBuilder 包含下列方法來擴充 物件的內容 StringBuilder :
方法 Append 會將字串、子字串、字元陣列、字元陣列的一部分、重複多次的單一字元,或基本數據類型的字串表示附加至 StringBuilder 物件。
方法 AppendLine 會將行終止符或字串連同行終止符附加至 StringBuilder 物件。
方法會將AppendFormat複合格式字串附加至 StringBuilder 物件。 結果字串中包含的物件字串表示可以反映目前系統文化特性或指定文化特性的格式慣例。
方法 Insert 會插入字串、子字串、字串、字串、字串的多個重複、字元陣列、字元陣列的一部分,或物件中指定位置之基本數據類型的 StringBuilder 字串表示。 位置是由以零起始的索引所定義。
下列範例會使用Append、 AppendLineAppendFormat和 Insert 方法來展開 物件的文字StringBuilder。
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 <
從 StringBuilder 物件中刪除文字
類別 StringBuilder 包含可減少目前 StringBuilder 實例大小的方法。 方法 Clear 會移除所有字元,並將屬性設定 Length 為零。 方法 Remove 會刪除從特定索引位置開始的指定字元數。 此外,您可以將物件的 Length 屬性設定為小於目前實例長度的值,以從對象的結尾StringBuilder移除字元。
下列範例會從 StringBuilder 物件中移除部分文字、顯示其產生的容量、最大容量和長度屬性值,然後呼叫 Clear 方法,以從 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
修改 StringBuilder 物件中的文字
方法 StringBuilder.Replace 會取代整個 StringBuilder 物件或特定字元範圍中所有出現的字元或字串。 下列範例會 Replace 使用 方法,將 物件中的所有 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?
在 StringBuilder 物件中搜尋文字
類別StringBuilder不包含與類別所提供的 String 、 String.IndexOf和 String.StartsWith 方法類似的String.Contains方法,可讓您搜尋物件中特定字元或子字串。 判斷子字串是否存在或起始字元位置,需要您使用字串搜尋方法或正則表達式方法來搜尋 String 值。 有四種方式可以實作這類搜尋,如下表所示。
技巧 | 優點 | 缺點 |
---|---|---|
在將字串值新增至 物件之前, StringBuilder 先搜尋字串值。 | 適用於判斷子字串是否存在。 | 當子字串的索引位置很重要時,便無法使用。 |
呼叫 ToString 並搜尋傳 String 回的物件。 | 如果您將所有文字指派給 StringBuilder 對象,然後開始修改它,則很容易使用。 | 如果您必須先進行修改,才能將所有文字新增至 StringBuilder 物件,則重複呼叫 ToString 。 如果您要進行變更,您必須記得從物件的文字結尾 StringBuilder 工作。 |
Chars[]使用屬性來循序搜尋字元範圍。 | 如果您擔心個別字元或小型子字串,則很有用。 | 如果要搜尋的字元數很大,或搜尋邏輯很複雜,則很麻煩。 針對透過重複的方法呼叫而成長非常大的對象,產生非常差的效能。 |
將 StringBuilder 物件轉換成 String 物件,並在物件上 String 執行修改。 | 如果修改數目很小,則很有用。 | 如果修改數目很大,則否定 類別的 StringBuilder 效能優點。 |
讓我們更詳細地檢查這些技術。
如果搜尋的目標是要判斷特定子字串是否存在(也就是說,如果您對子字串的位置不感興趣),則可以先搜尋字串,再將它們儲存在物件中 StringBuilder 。 下列範例提供一個可能的實作。 它會定義類別
StringBuilderFinder
,其建構函式會傳遞對象的 StringBuilder 參考,以及要尋找在字串中的子字串。 在此情況下,此範例會嘗試判斷記錄的溫度是否在華氏或攝氏,並將適當的簡介文字新增至對象的開頭 StringBuilder 。 隨機數產生器可用來選取數位,其中包含攝氏度或華氏度的數據。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
StringBuilder.ToString呼叫 方法,將 對象String轉換成 StringBuilder 物件。 您可以使用 或 String.StartsWith等String.LastIndexOf方法來搜尋字串,也可以使用正則表達式和 Regex 類別來搜尋模式。 由於和 String 物件都StringBuilder使用UTF-16編碼來儲存字元,因此這兩個物件中的字元、子字串和正則表達式的索引位置都相同。 這可讓您使用 StringBuilder 方法,在物件中找到 String 該文字的相同位置進行變更。
注意
如果您採用這種方法,您應該從對象的結尾 StringBuilder 到它的開頭工作,這樣您就不必重複地將 StringBuilder 對象轉換成字串。
下列範例將示範這個方法。 它會在物件中 StringBuilder 儲存四個英文字母的出現次數。 然後,它會將文字 String 轉換成 物件,並使用正則表達式來識別每個四個字元序列的起始位置。 最後,它會在每個四個字元序列之前新增底線,但第一個序列除外,並將序列的第一個字元轉換成大寫。
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
StringBuilder.Chars[]使用屬性來循序搜尋 物件中的StringBuilder字元範圍。 如果要搜尋的字元數很大,或搜尋邏輯特別複雜,這個方法可能並不實用。 如需非常大型區塊 StringBuilder 物件之逐字元索引型存取的效能影響,請參閱 屬性的檔 StringBuilder.Chars[] 。
下列範例的功能與上一個範例相同,但實作不同。 它會使用 Chars[] 屬性來偵測字元值何時變更、在該位置插入底線,並將新序列中的第一個字元轉換成大寫。
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
將所有未修改的文字儲存在物件中StringBuilder,呼叫 StringBuilder.ToString 方法將對象String轉換成 StringBuilder 物件,並在對象上String執行修改。 如果您只有一些修改,則可以使用此方法;否則,使用不可變字串的成本可能會否定使用 StringBuilder 物件的效能優點。
下列範例的功能與前兩個範例相同,但實作不同。 它會建立 StringBuilder 物件、將它 String 轉換成 物件,然後使用正則表達式在字串上執行所有剩餘的修改。 方法 Regex.Replace(String, String, MatchEvaluator) 會使用 Lambda 運算式,在每個相符項目上執行取代。
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
將 StringBuilder 物件轉換為字串
您必須先將 StringBuilder 物件轉換成 String 物件,才能將 StringBuilder 物件所代表的字串傳遞給具有 String 參數的方法,或在使用者介面中加以顯示。 您可以呼叫 StringBuilder.ToString 方法來執行此轉換。 如需圖例,請參閱上一個範例,它會呼叫 ToString 方法,將對象轉換成 StringBuilder 字串,以便傳遞至正則表達式方法。