IndexOf 返回 -1 表示未找到子串,主因是默认区分大小写、不自动去除首尾空格,或存在零宽字符等隐藏码点;应使用Trim()、OrdinalIgnoreCase或检查Unicode码点排查。

用 IndexOf 查子串位置时返回 -1 是为什么
返回 -1 表示没找到,但实际常因大小写或空白字符误判。C# 默认区分大小写,且不会自动 Trim 前后空格。
- 检查是否需要忽略大小写:
str.IndexOf(sub, StringComparison.OrdinalIgnoreCase) - 确认源字符串和子串都没有隐藏字符(比如
u200B零宽空格),可用str.Select(c => (int)c)快速排查异常码点 - 若子串来自用户输入或文件读取,先调用
.Trim()再搜索,避免首尾空格干扰
用 Contains 判断存在性却漏匹配
Contains 是 IndexOf >= 0 的封装,问题根源和上面一致,但它不暴露位置信息,排错更难。
- 不要用
Contains替代IndexOf做调试——它掩盖了“到底在哪没找到”这个关键线索 - 如果逻辑依赖“存在即合法”,但实际要容错,改用
str.IndexOf(sub, StringComparison.Ordinal) >= 0,明确指定比较方式 - 注意:
StringComparison.Ordinal比CurrentCulture更快也更可预测,除非真在做本地化文本搜索
正则表达式 Regex.Match 匹配失败却不报错
正则失败默认静默返回 Match.Success == false,容易被忽略,尤其当模式含转义或量词时。
- 写完正则先用在线工具(如 regex101)验证,特别注意 C# 字符串字面量需双反斜杠:
@"d{3}-d{4}"或"\d{3}-\d{4}" - 匹配前加判断:
if (!Regex.IsMatch(str, pattern)) { /* 记录 str 和 pattern 值 */ },避免线上静默跳过 - 性能敏感场景慎用正则查简单子串——
IndexOf比Regex.Match快 10 倍以上,纯文本查找没必要上正则
在长文本中反复查找多个子串导致性能骤降
逐个调用 IndexOf 并切片再查,会触发大量字符串分配和内存拷贝。
- 用
ReadOnlySpan替代string参数(.NET Core 2.1+):span.IndexOf(sub.AsSpan(), StringComparison.Ordinal),零分配 - 若需找所有匹配位置,别用
while ((i = str.IndexOf(sub, i)) != -1)这种易漏边界的方式,改用Regex.Matches或手写状态机(仅当子串固定且数量极多时) - 对超长日志类文本,考虑预处理:用
Memory+SpanReader流式扫描,避免一次性加载整段到内存
真实项目里最常卡住人的,不是“找不到函数”,而是默认比较行为和字符串不可见字符——多打一行 Console.WriteLine($"'{str}' -> {(int)str[0]}") 往往比翻文档更快定位问题。











