Substring易崩因未兜底,需先检查长度;Split默认保留空项且区分大小写;截取某字符后内容应结合IndexOf与Substring并判断返回值;Replace和Remove语义不同,删前缀应先StartsWith再Substring。

Substring 容易崩,不是方法有问题,是你没兜底。直接写 str.Substring(str.Length - 3) 而不检查长度,只要 str 长度小于 3,立刻抛 ArgumentOutOfRangeException——这是新手踩得最多的一坑。
用 Substring 截末尾 N 位前,必须先判断长度
想取后 5 个字符?别急着算索引。C# 的 Substring 不做越界保护,它只信你传的数是对的。
- 错误写法:
str.Substring(str.Length - 5)——str是"ab"就直接炸 - 安全写法:先判断
if (str.Length >= 5) { str.Substring(str.Length - 5); } - 更通用的兜底:用
Math.Max(0, Math.Min(startIndex, str.Length))包一层,但注意这只能防负索引,不能防startIndex + length > str.Length,所以带长度参数时仍需额外校验
用 Split 分割字符串时,空项和大小写容易被忽略
Split 看似简单,但默认行为会悄悄留空字符串,且对大小写敏感——这两点在解析日志、CSV 或用户输入时特别容易翻车。
- 默认不清理空项:
"a,,b".Split(',') → ["a", "", "b"],如果你遍历输出,中间那个空串可能引发后续逻辑异常 - 加
StringSplitOptions.RemoveEmptyEntries才能去掉空项:"a,,b".Split(',', StringSplitOptions.RemoveEmptyEntries) - 分隔符是字符串数组时(比如
new string[] { "and", "or" }),默认也区分大小写;需要忽略大小写就得自己转小写再切,或用正则
想截取“某个字符之后的内容”,别硬算索引,用 IndexOf + Substring 组合
比如从 "user@domain.com" 中取域名部分,或者从 "path/to/file.txt" 中取文件名。这类需求靠肉眼数位置不现实,也不可维护。
- 正确姿势:
int i = email.IndexOf('@'); if (i >= 0) domain = email.Substring(i + 1); - 注意
IndexOf返回-1表示未找到,必须判断,否则Substring(-1 + 1)变成Substring(0)看似能跑,但语义已错 - 如果要取“最后一次出现的位置”,用
LastIndexOf,比如取扩展名:int dot = path.LastIndexOf('.'); if (dot > 0) ext = path.Substring(dot + 1);
Replace 和 Remove 不是截取,但常被误当截取用
看到“删掉某段”“替换掉前缀”,有人第一反应写 Replace("prefix", "") 或 Remove(0, 6)。它们能达成效果,但语义和边界行为完全不同。
-
Replace是全局替换,"preprefix".Replace("prefix", "")会变成"pre",而不是你想要的“只删开头” -
Remove是按位置删,但它不检查范围——str.Remove(10, 5)在str.Length == 12时合法,但str.Length == 8就抛异常,和Substring同样脆弱 - 真要“安全删前缀”,推荐先用
StartsWith判断,再用Substring跳过:if (str.StartsWith("prefix")) str = str.Substring("prefix".Length);
实际项目里最麻烦的不是语法不会写,而是同一段截取逻辑在不同长度输入下表现不一致——比如空字符串、null、超短字符串、含 Unicode 补充字符的字符串。这些边界情况,光看文档容易漏,必须在测试里显式覆盖。











