本文涵蓋三種字串操作:正則表達式模式匹配, System.Text.RegularExpressions.Regex對 ,無分配搜尋, ReadOnlySpan<T>以及選擇 StringComparison 一個值以進行正確且快速的比較。
透過正則表達式尋找特定文本
該 System.Text.RegularExpressions.Regex 類別搜尋字串以尋找模式,而非固定子字串。 靜態 Regex.IsMatch 方法則會接收輸入字串、一個模式以及可選 RegexOptions 的旗標。
以下範例會在每句中搜尋 the 或 their,且不分格。 模式 the(ir)?\s 匹配 the ,後接 ir,接著空白字元:
| 樣式 | Meaning |
|---|---|
the |
與字面文字相符 the |
(ir)? |
匹配 0 或 1 的出現 ir |
\s |
匹配空白字元 |
string[] sentences =
[
"Put the water over there.",
"They're quite thirsty.",
"Their water bottles broke."
];
string pattern = @"the(ir)?\s";
foreach (string s in sentences)
{
Console.Write($"{s,28}");
if (Regex.IsMatch(s, pattern, RegexOptions.IgnoreCase))
{
Console.WriteLine($" (match for '{pattern}' found)");
}
else
{
Console.WriteLine();
}
}
驗證字串是否符合模式
要檢查整個輸入是否符合形狀,請用 ^ 和 $錨定該圖案。 以下範例驗證每個字串為美式電話號碼:三位數、三位數、四位數,並以破折號分隔:
| 樣式 | Meaning |
|---|---|
^ |
與字串的開頭相符 |
\d{3} |
完全匹配三位數字元 |
- |
匹配字面 - 上的字面角色 |
\d{4} |
完全匹配四個位數字元 |
$ |
匹配繩尾 |
string[] numbers =
[
"123-555-0190",
"444-234-22450",
"690-555-0178",
"146-893-232",
"146-555-0122",
"4007-555-0111",
"407-555-0111",
"407-2-5555",
"407-555-8974",
"407-2ab-5555",
"690-555-8148",
"146-893-232-"
];
string pattern = """^\d{3}-\d{3}-\d{4}$""";
foreach (string s in numbers)
{
Console.Write($"{s,14}");
Console.WriteLine(Regex.IsMatch(s, pattern) ? " - valid" : " - invalid");
}
完整模式語法請參見 正則表達式語言 - 快速參考。
請在方法與正則表達式之間 string 選擇
string 方法並 Regex 解決重疊問題。 當你搜尋的文字是字面值、已知的前綴或後綴,或固定分隔符時,建議 string 使用方法。 它們更簡單且更快,因為不需要支付編譯和執行模式的成本。 當搜尋目標為圖形時,請選擇Regex搜尋,例如交替、可選群組、重複字元類別或錨定驗證。 一般來說,如果你能把搜尋寫成一到兩次string.Contains / / StartsWithIndexOf通話,就這麼做。
搜尋 ReadOnlySpan<char>
當你解析大型輸入或在熱路徑上搜尋時,和string.Split的每次通話分配string.Substring可能會佔據主導地位。
ReadOnlySpan<char> 提供您對現有字串(或陣列、堆疊緩衝區)的檢視,無需複製,並提供 MemoryExtensions 基於 string span 的常見方法等價功能,包括 IndexOf:
ReadOnlySpan<char> input = "key1=alpha;key2=beta;key3=gamma".AsSpan();
ReadOnlySpan<char> needle = "key2=".AsSpan();
int start = input.IndexOf(needle);
if (start >= 0)
{
ReadOnlySpan<char> rest = input[(start + needle.Length)..];
int end = rest.IndexOf(';');
ReadOnlySpan<char> value = end >= 0 ? rest[..end] : rest;
Console.WriteLine($"key2 = {value}");
}
// => key2 = beta
基於張寬的搜尋避免了分配,因為切片(input[start..], rest[..end])只是原始字元上的視窗。 同樣的方法也適用於解析鍵值清單、標頭及其他分隔文字,而無需呼叫 Substring。
StringComparison 的效能考量事項
大多數 string 實例方法都有過載,可以接受一個 StringComparison 值。
String.Equals(String)例如預設為序數,但String.Compare(String, String)String.IndexOf(String)預設為當前文化。 這個差異有兩個重要方面:
- 速度。 序數比較是一種位元組對位元組的測試,以緊密且向量化的迴圈進行。 文化感知比較會參考排序表、行走組合角色,並套用特定地區規則。 對於相同的輸入,速度可能會慢一個數量級。
- 正確性。 文化意識的比較可能會
i/I讓你意外出現(土耳其人、德國ß人、ss連字)。 這種行為對於排序使用者看到的名稱是正確的,但在解析識別碼、路徑或協定標記時則錯誤。
對於機器定義的文字,例如檔名、URL、HTTP 標頭、識別碼和設定鍵,分別是傳遞 StringComparison.Ordinal 或 StringComparison.OrdinalIgnoreCase 明確。 為顯示給使用者的自然語言文字保留文化意識值。 如需完整指引,請參閱