C#中查找字符串子串的操作几乎贯穿所有文本处理场景,从简单的文本匹配到复杂的业务规则校验都会用到,掌握正确的查找方法和问题排查思路能减少很多不必要的开发时间消耗。

C#查找子串的常用方法
1. 使用IndexOf方法
IndexOf是最常用的子串查找方法,返回子串在原字符串中首次出现的索引位置,如果没找到则返回-1。它支持设置查找起始位置和比较规则。
using System;
class Program
{
static void Main()
{
string mainStr = "Hello World, C# is powerful";
string subStr = "World";
// 基础查找
int index = mainStr.IndexOf(subStr);
Console.WriteLine($"子串首次出现位置:{index}"); // 输出6
// 从指定位置开始查找
int indexFrom5 = mainStr.IndexOf(subStr, 5);
Console.WriteLine($"从索引5开始查找的位置:{indexFrom5}"); // 输出6
// 忽略大小写查找
int ignoreCaseIndex = mainStr.IndexOf(subStr, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"忽略大小写查找位置:{ignoreCaseIndex}"); // 输出6
}
}
2. 使用Contains方法
Contains是更简洁的判断方式,直接返回布尔值表示原字符串是否包含目标子串,内部其实也是基于IndexOf实现的。
using System;
class Program
{
static void Main()
{
string mainStr = "C# string operation";
string subStr = "string";
bool hasSub = mainStr.Contains(subStr);
Console.WriteLine($"是否包含子串:{hasSub}"); // 输出True
// 忽略大小写的Contains需要自行封装
bool ignoreCaseHas = mainStr.IndexOf(subStr, StringComparison.OrdinalIgnoreCase) >= 0;
Console.WriteLine($"忽略大小写是否包含:{ignoreCaseHas}"); // 输出True
}
}
3. 使用Substring配合定位查找
如果需要获取匹配到的子串内容,可以结合IndexOf和Substring使用,先找到位置再截取对应长度的子串。
using System;
class Program
{
static void Main()
{
string mainStr = "user_name:zhangsan,age:20";
string subStr = "user_name:";
int index = mainStr.IndexOf(subStr);
if (index >= 0)
{
// 找到子串后截取后面的内容,直到遇到逗号
int commaIndex = mainStr.IndexOf(",", index);
string userName = commaIndex > index ?
mainStr.Substring(index + subStr.Length, commaIndex - index - subStr.Length) :
mainStr.Substring(index + subStr.Length);
Console.WriteLine($"获取到的用户名:{userName}"); // 输出zhangsan
}
}
}
4. 使用正则表达式查找
当查找规则比较复杂时,比如匹配特定格式的字符串,可以使用正则表达式的Regex.Match方法。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string mainStr = "订单号:2024050112345,金额:100元";
// 查找连续的5位以上数字作为订单号
Match match = Regex.Match(mainStr, @"d{5,}");
if (match.Success)
{
Console.WriteLine($"匹配到的订单号:{match.Value}"); // 输出2024050112345
}
}
}
常见问题与排错指南
问题1:查找结果不符合预期,明明有子串却返回-1
这是最常见的问题,多数情况是大小写不匹配导致的。C#的字符串查找默认是大小写敏感的,如果原字符串和目标子串大小写不一致就会匹配失败。
排查方法:先检查两个字符串的实际内容,确认大小写是否一致,如果需要忽略大小写,使用StringComparison.OrdinalIgnoreCase参数。
问题2:查找空字符串或null时抛出异常
如果传入的子串是null,IndexOf和Contains都会抛出ArgumentNullException;如果子串是空字符串,IndexOf会返回0,因为空字符串默认在首位存在。
解决方案:查找前先对子串做非空校验,明确空字符串的处理逻辑。
using System;
class Program
{
static void Main()
{
string mainStr = "test string";
string subStr = null;
// 先校验避免异常
if (!string.IsNullOrEmpty(subStr))
{
int index = mainStr.IndexOf(subStr);
}
else
{
Console.WriteLine("子串为空,无法执行查找");
}
}
}
问题3:正则表达式查找特殊字符匹配失败
如果要查找的子串包含正则特殊字符,比如.、*、?等,直接使用正则查找会被识别为元字符,导致匹配错误。
解决方案:使用Regex.Escape方法对子串进行转义,把特殊字符转为普通字符。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string mainStr = "文件版本是1.0.2";
string subStr = "1.0.2";
// 转义特殊字符后再匹配
string escapedSub = Regex.Escape(subStr);
Match match = Regex.Match(mainStr, escapedSub);
Console.WriteLine($"正则匹配结果:{match.Success}"); // 输出True
}
}
问题4:查找范围设置错误导致漏匹配
使用IndexOf的重载方法指定查找起始位置时,如果起始位置超出字符串长度,或者计算错误,会导致后续的内容没有被查找。
排查方法:打印起始位置的值,确认是否在合法范围内,同时检查循环查找时的索引递增逻辑是否正确。
问题5:截取子串时长度计算错误导致异常
使用Substring截取子串时,如果计算的长度超过原字符串剩余长度,会抛出ArgumentOutOfRangeException。
解决方案:截取前先判断剩余长度是否足够,或者直接使用Substring(startIndex)重载,从起始位置截取到字符串末尾,避免长度计算错误。
| 查找方法 | 适用场景 | 返回值类型 | 注意事项 |
|---|---|---|---|
| IndexOf | 需要知道子串位置或判断是否存在 | int,不存在返回-1 | 默认大小写敏感,支持比较规则参数 |
| Contains | 只需要判断是否存在子串 | bool | 无内置忽略大小写重载,需自行封装 |
| 正则Match | 复杂规则匹配 | Match对象,Success判断是否存在 | 特殊字符需要转义,性能略低于原生方法 |
在实际开发中,优先选择符合场景的原生查找方法,复杂规则再使用正则,同时做好边界条件的校验,就能避免大部分子串查找相关的问题。