在字串處理中,尋找特定字元出現的所有位置是常見需求。本文示範使用 ToCharArray 轉換字串為字元陣列,配合迴圈查找的基本做法,並提供更現代化的 LINQ 與 IndexOf 進階寫法。
using System;
using System.Windows.Forms;
public class CharPositionFinder
{
public void FindAllPositions(string input, char target)
{
char[] charArray = input.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (charArray[i] == target)
{
MessageBox.Show(
$"字元 '{target}' 在字串 \"{input}\" 中的位置為:{i}",
"查找結果");
}
}
}
}
public void FindAllPositionsImproved(string input, char target)
{
var positions = new List();
char[] charArray = input.ToCharArray();
for (int i = 0; i < charArray.Length; i++)
{
if (charArray[i] == target)
positions.Add(i);
}
if (positions.Count > 0)
{
MessageBox.Show(
$"字元 '{target}' 在 \"{input}\" 中出現 {positions.Count} 次,位置:[{string.Join(", ", positions)}]",
"查找結果");
}
else
{
MessageBox.Show($"字元 '{target}' 在 \"{input}\" 中未找到", "查找結果");
}
}
using System.Linq;
public IEnumerable FindPositionsLinq(string input, char target)
{
return input.Select((c, index) => c == target ? index : -1)
.Where(index => index != -1);
}
// 使用方式
var positions = FindPositionsLinq("hello world", 'l').ToList();
// 結果:[2, 3, 9]
public List FindPositionsIndexOf(string input, char target)
{
var positions = new List();
int index = input.IndexOf(target);
while (index != -1)
{
positions.Add(index);
index = input.IndexOf(target, index + 1);
}
return positions;
}
| 方法 | 時間複雜度 | 記憶體 | 適用場景 |
|---|---|---|---|
| ToCharArray + for | O(n) | O(n) 額外陣列 | 教學、簡單案例 |
| LINQ Select/Where | O(n) | O(n) 疊代器 | 函數式風格、鏈式操作 |
| IndexOf 迴圈 | O(n) | O(1) 額外 | 大字串、高效能需求 |
| Regex.Matches | O(n) | O(m) 比對結果 | 複雜模式匹配 |
public List FindSubstringPositions(string input, string substring)
{
if (string.IsNullOrEmpty(substring))
return new List();
var positions = new List();
int index = input.IndexOf(substring, StringComparison.Ordinal);
while (index != -1)
{
positions.Add(index);
index = input.IndexOf(substring, index + 1, StringComparison.Ordinal);
}
return positions;
}
// 不區分大小寫版本
public List FindSubstringPositionsIgnoreCase(string input, string substring)
{
var positions = new List();
int index = input.IndexOf(substring, StringComparison.OrdinalIgnoreCase);
while (index != -1)
{
positions.Add(index);
index = input.IndexOf(substring, index + 1, StringComparison.OrdinalIgnoreCase);
}
return positions;
}
public partial class Form1 : Form
{
private TextBox txtInput;
private TextBox txtTarget;
private Button btnFind;
private ListBox lstResults;
public Form1()
{
InitializeComponent();
}
private void btnFind_Click(object sender, EventArgs e)
{
string input = txtInput.Text;
string target = txtTarget.Text;
lstResults.Items.Clear();
if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(target))
{
MessageBox.Show("請輸入字串與搜尋目標");
return;
}
if (target.Length == 1)
{
// 單字元搜尋
char c = target[0];
var positions = FindPositionsIndexOf(input, c);
DisplayResults(positions, c.ToString());
}
else
{
// 子字串搜尋
var positions = FindSubstringPositions(input, target);
DisplayResults(positions, target);
}
}
private void DisplayResults(List positions, string target)
{
if (positions.Count == 0)
{
lstResults.Items.Add($"未找到 '{target}'");
}
else
{
lstResults.Items.Add($"找到 {positions.Count} 個 '{target}':");
foreach (int pos in positions)
{
lstResults.Items.Add($" 位置 {pos} (第 {pos + 1} 個字元)");
}
}
}
// ... 上述尋找方法放在這裡
}
char(UTF-16 代理配對),ToCharArray 會拆分StringInfo 或 Rune (NET Core 3.0+) 處理 Unicode 字素簇
using System.Globalization;
// 正確處理 Unicode 字素簇
public List FindGraphemePositions(string input, string target)
{
var positions = new List();
StringInfo si = new StringInfo(input);
StringInfo targetSi = new StringInfo(target);
if (targetSi.LengthInTextElements != 1)
throw new ArgumentException("目標必須為單一字素簇");
string targetGrapheme = targetSi.SubstringByTextElements(0, 1);
for (int i = 0; i < si.LengthInTextElements; i++)
{
if (si.SubstringByTextElements(i, 1) == targetGrapheme)
positions.Add(si.ParseCombiningCharacters[i]);
}
return positions;
}
尋找字元位置的基本方法是遍歷字元陣列,但 IndexOf 迴圈效能最佳且記憶體效率最高。現代 C# 可使用 LINQ 簡化程式碼。處理 Unicode 字串時需注意代理配對問題,建議使用 StringInfo 或 Rune 正確處理字素簇。實務開發中建議封裝為擴充方法,方便重複使用。