TL; DR
如果你的目標是獲得一個String
對象的一塊或全部的StringBuilder
的內容,你應該使用其ToString
功能。但是如果你還沒有完成字符串的創建,最好將StringBuilder
作爲一個字符數組來操作,而不是創建一堆你不需要的字符串。
字符數組上的字符串操作可能因本地化或編碼而變得複雜,因爲字符串可以用多種方式進行編碼(例如UTF8或Unicode),但其字符(System.Char
)應該是16位的UTF16值。
我寫了下面的方法,如果它存在於StringBuilder
中,則返回字符串的索引,否則返回-1。您可以使用它來創建其他常見的String
方法,如Contains
,StartsWith
和EndsWith
。這種方法比其他方法更好,因爲它應該正確處理定位和套管,並且不會強制您在StringBuilder
上調用ToString
。如果您指定應該忽略大小寫,它會創建一個垃圾值,您可以通過使用Char.ToLower來解決此問題,以最大限度地節省內存,而不是像下面的函數那樣預先計算字符串的小寫字母。 編輯:此外,如果您使用UTF32編碼的字符串,則必須一次比較兩個字符,而不是一個字符。
除非你打算循環,使用大字符串,並進行操作或格式化,否則你可能更適合使用ToString
。
public static int IndexOf(this StringBuilder stringBuilder, string str, int startIndex = 0, int? count = null, CultureInfo culture = null, bool ignoreCase = false)
{
if (stringBuilder == null)
throw new ArgumentNullException("stringBuilder");
// No string to find.
if (str == null)
throw new ArgumentNullException("str");
if (str.Length == 0)
return -1;
// Make sure the start index is valid.
if (startIndex < 0 && startIndex < stringBuilder.Length)
throw new ArgumentOutOfRangeException("startIndex", startIndex, "The index must refer to a character within the string.");
// Now that we've validated the parameters, let's figure out how many characters there are to search.
var maxPositions = stringBuilder.Length - str.Length - startIndex;
if (maxPositions <= 0) return -1;
// If a count argument was supplied, make sure it's within range.
if (count.HasValue && (count <= 0 || count > maxPositions))
throw new ArgumentOutOfRangeException("count");
// Ensure that "count" has a value.
maxPositions = count ?? maxPositions;
if (count <= 0) return -1;
// If no culture is specified, use the current culture. This is how the string functions behave but
// in the case that we're working with a StringBuilder, we probably should default to Ordinal.
culture = culture ?? CultureInfo.CurrentCulture;
// If we're ignoring case, we need all the characters to be in culture-specific
// lower case for when we compare to the StringBuilder.
if (ignoreCase) str = str.ToLower(culture);
// Where the actual work gets done. Iterate through the string one character at a time.
for (int y = 0, x = startIndex, endIndex = startIndex + maxPositions; x <= endIndex; x++, y = 0)
{
// y is set to 0 at the beginning of the loop, and it is increased when we match the characters
// with the string we're searching for.
while (y < str.Length && str[y] == (ignoreCase ? Char.ToLower(str[x + y]) : str[x + y]))
y++;
// The while loop will stop early if the characters don't match. If it didn't stop
// early, that means we found a match, so we return the index of where we found the
// match.
if (y == str.Length)
return x;
}
// No matches.
return -1;
}
主要的原因一個一般採用StringBuilder
對象,而不是連接字符串是因爲內存的開銷,你承擔,因爲字符串是不可變的。當你在不使用StringBuilder
的情況下進行過多的字符串處理時,性能會受到影響,這通常是收集您創建的所有垃圾字符串的結果。
藉此例如:
string firstString = "1st",
secondString = "2nd",
thirdString = "3rd",
fourthString = "4th";
string all = firstString;
all += " & " + secondString;
all += " &" + thirdString;
all += "& " + fourthString + ".";
如果你運行這一點,在內存分析器打開它,你會發現一組字符串是這個樣子的:
"1st", "2nd", "3rd", "4th",
" & ", " & 2nd", "1st & 2nd"
" &", "&3rd", "1st & 2nd &3rd"
"& ", "& 4th", "& 4th."
"1st & 2nd &3rd& 4th."
這是我們在該範圍內創建的十四個對象,但是如果您沒有意識到每次添加運算符都會創建一個全新的字符串,那麼您每次可能認爲只有五個對象。那麼其他九個琴絃會發生什麼?他們在記憶中疲於奔命,直到垃圾收集者決定接收它們。
所以現在我的觀點是:如果你想找到一些關於StringBuilder
對象的東西,並且你不想打電話給ToString()
,這可能意味着你還沒有完成構建該字符串。如果您試圖查明構建器是否以「Foo」結尾,則撥打sb.ToString(sb.Length - 1, 3) == "Foo"
會很浪費,因爲您正在創建另一個字符串對象,在您撥打電話的那一刻變成孤兒和過時。
我的猜測是,您正在運行一個循環,將文本聚合到您的StringBuilder
中,並且您希望結束循環,或者如果最後幾個字符是您期望的某個標記值,則只需執行一些不同的操作。
反轉字符串並做一個'StartsWith(「world」)'也許? – PoweredByOrange
爲什麼你害怕'ToString'?這就是你如何使用StringBuilders – banging
@PoweredByOrange Hm ... StringBuilder沒有StartsWith方法,並且相反,它將會更加耗費性能,從最後開始檢查,char by char。 –