在 C# 開發中,String 類別提供多種搜尋子字串或字元的方法。最常用的是 IndexOf/LastIndexOf 與 IndexOfAny/LastIndexOfAny。雖然名稱相似,但適用情境與行為有顯著差異。本文將詳細比較這四個方法的簽章、回傳值、效能特性與實務用法,並附上完整範例程式碼。
| 方法 | 用途 | 搜尋方向 | 支援多目標 | 典型回傳值 |
|---|---|---|---|---|
IndexOf |
搜尋單一字元或子字串 | 由前往後 | 否 | 第一次出現的索引 (0-based),找不到回傳 -1 |
LastIndexOf |
搜尋單一字元或子字串 | 由後往前 | 否 | 最後一次出現的索引,找不到回傳 -1 |
IndexOfAny |
搜尋字元陣列中任一字元 | 由前往後 | 是 | 最早出現的任一字元索引,找不到回傳 -1 |
LastIndexOfAny |
搜尋字元陣列中任一字元 | 由後往前 | 是 | 最晚出現的任一字元索引,找不到回傳 -1 |
public int IndexOf(char value);
public int IndexOf(char value, int startIndex);
public int IndexOf(char value, int startIndex, int count);
public int IndexOf(string value);
public int IndexOf(string value, int startIndex);
public int IndexOf(string value, int startIndex, int count);
LastIndexOf 簽章完全相同,差別在搜尋方向。
value:要搜尋的字元或子字串。startIndex:開始搜尋的索引位置。count:從 startIndex 起要檢查的字元數(區間長度)。string s = "Hello";
// 尋找 'l' 第一次出現位置
int idx1 = s.IndexOf('l'); // 回傳 2
// 尋找 'l' 最後一次出現位置
int idx2 = s.LastIndexOf('l'); // 回傳 3
// 從索引 3 開始往後找 'l'
int idx3 = s.IndexOf('l', 3); // 回傳 3
// 在索引 0~2 範圍找 'l'
int idx4 = s.IndexOf('l', 0, 3); // 回傳 2
public int IndexOfAny(char[] anyOf);
public int IndexOfAny(char[] anyOf, int startIndex);
public int IndexOfAny(char[] anyOf, int startIndex, int count);
LastIndexOfAny 簽章相同,搜尋方向相反。
anyOf:字元陣列,方法會回傳陣列中「任一」字元最早/最晚出現的索引。startIndex、count:同 IndexOf。string s = "Hello World";
char[] vowels = { 'a', 'e', 'i', 'o', 'u' };
// 找第一個母音
int firstVowel = s.IndexOfAny(vowels); // 1 (e)
// 找最後一個母音
int lastVowel = s.LastIndexOfAny(vowels); // 7 (o)
// 從索引 5 開始找第一個母音
int firstAfter5 = s.IndexOfAny(vowels, 5); // 7 (o)
搜尋單一字元時,優先使用 char 多載而非 string,避免建立字串物件開銷。
所有四個方法皆區分大小寫。需不區分大小寫搜尋時,可先 ToLower() 或使用 CultureInfo.CompareInfo.IndexOf 搭配 CompareOptions.IgnoreCase。
若需同時取得第一次與最後一次位置,不要連呼 IndexOf 與 LastIndexOf(會掃描兩次),改用單次迴圈或 Regex 處理。
IndexOf("") 永遠回傳 0(空字串視為存在於開頭)。IndexOfAny(new char[0]) 永遠回傳 -1。| 場景 | 建議方法 | 說明 |
|---|---|---|
| 檢查字串是否包含特定關鍵字 | IndexOf(keyword) >= 0 |
最直觀、效能佳 |
| 解析 CSV/TSV 等分隔符號 | IndexOfAny(new[]{',','\t'}) |
一次檢查多種分隔符 |
| 從路徑取得檔名(找最後一個 \ 或 /) | LastIndexOfAny(new[]{'\\','/'}) |
跨平台路徑通用 |
| 移除字串尾端特定字元 | LastIndexOf + Substring |
配合長度計算 |
using System;
class StringSearchDemo
{
static void Main()
{
string text = "The quick brown fox jumps over the lazy dog.";
char[] punctuation = { '.', ',', ';', ':', '!', '?' };
Console.WriteLine($"原始字串:{text}");
Console.WriteLine($"長度:{text.Length}");
// IndexOf 範例
int firstO = text.IndexOf('o');
int lastO = text.LastIndexOf('o');
Console.WriteLine($"\n第一個 'o' 索引:{firstO}");
Console.WriteLine($"最後一個 'o' 索引:{lastO}");
// IndexOfAny 範例
int firstPunc = text.IndexOfAny(punctuation);
int lastPunc = text.LastIndexOfAny(punctuation);
Console.WriteLine($"\n第一個標點符號索引:{firstPunc} (字元:'{text[firstPunc]}')");
Console.WriteLine($"最後一個標點符號索引:{lastPunc} (字元:'{text[lastPunc]}')");
// 區間搜尋
int oInRange = text.IndexOf('o', 10, 15);
Console.WriteLine($"\n索引 10~24 範圍內第一個 'o':{oInRange}");
// 找不到時
int notFound = text.IndexOf('z', 0, 5);
Console.WriteLine($"\n前 5 字元找 'z':{notFound} (預期 -1)");
}
}
char[],不支援字串陣列;若需搜尋多個子字串,請改用 Regex 或自行迴圈。startIndex、count 限制搜尋範圍,可大幅提升長字串處理效能。