C# string 字符串方法大全:判空、查找、截取、分割、替换一篇讲透

C# string 字符串方法大全:判空、查找、截取、分割、替换一篇讲透

导语:string 就像一块刻好的石碑,字一旦刻上去就改不了,所有看起来"在修改"的方法(Replace、Trim、ToUpper......)其实都是重新刻一块新石头给你,原字符串纹丝不动。它的方法虽多,但按"判断、查找、截取分割、修改、拼接、比较"六大类来记就不会乱。本文把日常开发 90% 会用到的字符串方法全部配上可运行示例,适合入门学习和写代码时当速查表。

一、先记住 string 的三个基本事实

事实 1:string 是不可变的

字符串一旦创建,内容就不能再改。下面这段代码可以证明:

csharp 复制代码
string s = "ABC";
string s2 = s;
s += "DEF";                 // 不是在原字符串上写字,而是造了一个新字符串
Console.WriteLine(s);       // ABCDEF
Console.WriteLine(s2);      // ABC(s2 指向的旧字符串完全没变)

所以后面所有"修改类"方法(Replace、Trim、ToUpper、Substring 等)都有一个共同规律:不修改原字符串,而是返回一个新字符串,必须用变量接住返回值才有效。

事实 2:string 是引用类型,但 == 比较的是内容

csharp 复制代码
string a = "hello";
string b = "hel" + "lo";    // 运行时拼接,和 a 不是同一个对象
Console.WriteLine(a == b);              // True:string 重载了 ==,比较的是文本内容
Console.WriteLine(ReferenceEquals(a, b)); // False:两个对象在内存里不是同一个

所以字符串比较内容时,直接用 == 就行,这和普通引用类型用 == 比较地址不一样,C# 已经帮你处理好了。

事实 3:Length 和索引器是最基础的两个成员

csharp 复制代码
string s = "abcdef";
Console.WriteLine(s.Length);   // 6:字符个数
Console.WriteLine(s[0]);       // a:像数组一样按下标读字符,下标从 0 开始
// s[0] = 'x';                // 报错:字符串不可变,索引器只能读不能写

【插图 1:string 方法分类地图】

二、判空与判断类方法

2.1 三种"空"先分清:null、""、空白

这是初学者最容易混的三个状态:

  • null:变量根本没有指向任何字符串(连石头都没有)。
  • ""(或 string.Empty):字符串存在,但里面一个字符都没有(有石头,没刻字)。
  • " ":字符串里装的是空格、制表符这类空白字符(刻了字,只是看不见)。

2.2 IsNullOrEmpty 和 IsNullOrWhiteSpace

csharp 复制代码
string s1 = null;
string s2 = "";
string s3 = "   ";
string s4 = "abc";

// IsNullOrEmpty:null 或空字符串都算 true
Console.WriteLine(string.IsNullOrEmpty(s1));  // True
Console.WriteLine(string.IsNullOrEmpty(s2));  // True
Console.WriteLine(string.IsNullOrEmpty(s3));  // False(空白不是空字符串)
Console.WriteLine(string.IsNullOrEmpty(s4));  // False

// IsNullOrWhiteSpace:null、空、只含空白都算 true
Console.WriteLine(string.IsNullOrWhiteSpace(s3));  // True
Console.WriteLine(string.IsNullOrWhiteSpace(s4));  // False

【插图 2:null、空字符串、空白的判断结果对比】

实战中判断一个字符串"能不能用",优先用 IsNullOrWhiteSpace,因为用户输入几个空格通常也应当作没填。

2.3 Contains、StartsWith、EndsWith

csharp 复制代码
string s = "Hello World";

// Contains:是否包含某个子串
Console.WriteLine(s.Contains("World"));   // True
Console.WriteLine(s.Contains("world"));   // False(默认区分大小写)

// StartsWith / EndsWith:以什么开头 / 结尾
Console.WriteLine(s.StartsWith("Hello")); // True
Console.WriteLine(s.EndsWith("World"));   // True

版本说明:在 .NET Core 2.1 / .NET 5 及更高版本中,这三个方法还支持直接传 char 字符,比如 s.Contains('W');老版本只支持字符串参数。

2.4 忽略大小写的判断

判断时不区分大小写,不要先 ToLower() 再比,推荐直接给比较方式:

csharp 复制代码
string s = "Hello World";
bool ok = s.StartsWith("hello", StringComparison.OrdinalIgnoreCase);
Console.WriteLine(ok);   // True

StringComparison 是什么、为什么推荐 Ordinal,第七节会专门讲。

三、查找位置类方法

3.1 IndexOf 和 LastIndexOf

csharp 复制代码
string s = "banana";

// IndexOf:从前往后找,返回第一次出现的下标,找不到返回 -1
Console.WriteLine(s.IndexOf('a'));       // 1
Console.WriteLine(s.IndexOf("na"));      // 2
Console.WriteLine(s.IndexOf('x'));       // -1

// LastIndexOf:从后往前找,返回最后一次出现的下标
Console.WriteLine(s.LastIndexOf('a'));   // 5

3.2 IndexOfAny 和 LastIndexOfAny

IndexOfAny 一次给一组字符,谁先出现就返回谁的位置:

csharp 复制代码
string s = "Hello, World!";
char[] punctuation = { ',', '!', '?' };

Console.WriteLine(s.IndexOfAny(punctuation));       // 5(逗号先出现)
Console.WriteLine(s.LastIndexOfAny(punctuation));   // 12(感叹号在最后)

3.3 方法归纳

方法 作用 找不到时
IndexOf(char/string) 从前往后找第一次出现的位置 返回 -1
LastIndexOf(...) 从后往前找最后一次出现的位置 返回 -1
IndexOfAny(char[]) 一组字符中谁先出现 返回 -1
LastIndexOfAny(char[]) 一组字符中谁最后出现 返回 -1

四、截取与分割类方法

4.1 Substring:从指定位置截取

csharp 复制代码
string s = "Hello World";

// 一个参数:从下标 6 一直截到末尾
Console.WriteLine(s.Substring(6));      // World

// 两个参数:从下标 0 开始,截取 5 个字符
Console.WriteLine(s.Substring(0, 5));   // Hello

4.2 范围运算符:更简洁的截取方式(C# 8.0 及以上)

C# 8 引入了范围运算符 ..,截取字符串时比 Substring 更直观:

csharp 复制代码
string s = "Hello World";

Console.WriteLine(s[..5]);    // Hello:从头截到下标 5 之前
Console.WriteLine(s[6..]);    // World:从下标 6 截到末尾
Console.WriteLine(s[2..5]);   // llo:从下标 2 截到下标 5 之前

4.3 Split:按分隔符切成数组

csharp 复制代码
string csv = "a,b,,c,";

// 直接切:连续分隔符和末尾分隔符会产生空字符串条目
string[] r1 = csv.Split(',');
// 结果:["a", "b", "", "c", ""]

// RemoveEmptyEntries:自动去掉空条目
string[] r2 = csv.Split(',', StringSplitOptions.RemoveEmptyEntries);
// 结果:["a", "b", "c"]

StringSplitOptions 常用取值:

取值 作用
None 默认,保留空条目
RemoveEmptyEntries 去掉空字符串条目
TrimEntries 自动去掉每个条目两端的空白(.NET 5 及以上)
`RemoveEmptyEntries TrimEntries`

还可以一次传多个分隔符:

csharp 复制代码
string s = "a-b,c";
string[] parts = s.Split(new[] { '-', ',' });
// 结果:["a", "b", "c"]

五、修改与转换类方法

【插图 3:修改类方法返回新字符串,原字符串不变】

5.1 Replace:替换

csharp 复制代码
string s = "a-b-c";
string result = s.Replace("-", "_");   // 所有 "-" 都替换,不只是第一个
Console.WriteLine(result);             // a_b_c
Console.WriteLine(s);                  // a-b-c(原字符串没变)

5.2 Trim、Pad:去空白和补位

csharp 复制代码
// Trim:去掉两端空白(也可以指定要去掉的字符)
Console.WriteLine("  hi  ".Trim());          // hi
Console.WriteLine("**hi**".Trim('*'));       // hi
Console.WriteLine("  hi  ".TrimStart());     // hi(只去开头)
Console.WriteLine("  hi  ".TrimEnd());       // hi(只去结尾)

// PadLeft / PadRight:长度不够时用指定字符补齐
Console.WriteLine("42".PadLeft(5, '0'));     // 00042(补零场景很常用)
Console.WriteLine("42".PadRight(5, '*'));    // 42***

5.3 大小写转换

csharp 复制代码
Console.WriteLine("hello".ToUpper());   // HELLO
Console.WriteLine("HELLO".ToLower());   // hello

5.4 Insert 和 Remove:插入与删除

csharp 复制代码
// Insert:在下标位置插入内容
Console.WriteLine("Hello World".Insert(5, ","));   // Hello, World

// Remove:从下标位置开始删除若干字符
Console.WriteLine("Hello, World".Remove(5, 2));    // HelloWorld

5.5 ToCharArray:转成字符数组

需要逐个字符处理时,先转成数组:

csharp 复制代码
char[] chars = "abc".ToCharArray();
foreach (char c in chars)
{
    Console.WriteLine(c);
}

5.6 方法归纳表

方法 作用 关键点
Replace(old, new) 替换全部匹配项 有 char 和 string 两个重载
Trim() / TrimStart() / TrimEnd() 去两端空白或指定字符 不去中间的空白
PadLeft() / PadRight() 补位到指定长度 常用于补零、对齐
ToUpper() / ToLower() 转大写 / 小写 同样返回新字符串
Insert(index, value) 指定位置插入 下标从 0 开始
Remove(start, length) 指定位置删除 按位置删,不是按内容
ToCharArray() 转字符数组 可配合排序、反转等算法

六、拼接、格式化与新语法

6.1 Concat 和 Join(静态方法)

csharp 复制代码
// Concat:首尾相接,不加分隔符
Console.WriteLine(string.Concat("a", "b", "c"));   // abc

// Join:用分隔符把多个值连起来
Console.WriteLine(string.Join(",", 1, 2, 3));       // 1,2,3
Console.WriteLine(string.Join("、", new[] { "看书", "跑步" })); // 看书、跑步

6.2 Format 和字符串插值

csharp 复制代码
// Format:用占位符 {0}、{1} 拼接
string s1 = string.Format("姓名:{0},年龄:{1}", "张三", 18);

// 字符串插值:直接在 { } 里写变量,更直观,日常首选
string name = "张三";
int age = 18;
string s2 = $"姓名:{name},年龄:{age}";

6.3 原始字符串(C# 11.0 及以上)

路径、JSON、SQL 里有大量引号和反斜杠时,用三个双引号包裹的原始字符串,既不用转义,还能保留缩进:

csharp 复制代码
string json = """
{
  "name": "张三",
  "age": 18
}
""";

循环里大量拼接、动态拼装 SQL/HTML 等场景,应该用 StringBuilder,可以参考我之前的《C# StringBuilder 详解》;按规则匹配、提取文本的场景(邮箱、手机号、提取数字)则用正则,可以参考《C# 正则表达式零基础入门》。

七、比较类方法与 StringComparison

7.1 Equals 和 Compare

csharp 复制代码
// Equals:判断两个字符串是否相等
Console.WriteLine(string.Equals("a", "a"));  // True
Console.WriteLine("a".Equals("A", StringComparison.OrdinalIgnoreCase)); // True

// Compare:比较大小,小于返回 -1,等于返回 0,大于返回 1,常用于排序
Console.WriteLine(string.Compare("a", "b"));  // -1
Console.WriteLine(string.Compare("b", "a"));  // 1
Console.WriteLine(string.Compare("a", "a"));  // 0

// CompareOrdinal:纯粹按字符编码数值比较,不考虑语言文化
Console.WriteLine(string.CompareOrdinal("a", "b"));  // -1

7.2 StringComparison 枚举速查

取值 含义 典型用途
Ordinal 按字符原始数值逐字节比较 路径、协议、关键字等精确匹配
OrdinalIgnoreCase 同上,忽略大小写 不区分大小写的关键字判断(推荐)
CurrentCulture 按当前系统语言文化比较(默认行为) 界面显示、文本排序
CurrentCultureIgnoreCase 同上,忽略大小写 不区分大小写的用户输入
InvariantCulture 与具体语言文化无关的固定格式 持久化数据格式(较少用)

八、常见坑

  1. 把修改类方法当成"原地修改",没有接住返回值。 s.Replace("-", "_") 执行完 s 还是原样,新字符串在返回值里被丢掉了。正确写法是 s = s.Replace("-", "_");所有 Replace、Trim、ToUpper 类方法都一样。

  2. 判空时直接用 s == "" 或 s.Length == 0,遇到 null 直接抛 NullReferenceException。 先判空再操作,统一用 string.IsNullOrEmpty(s);用户输入类场景用 IsNullOrWhiteSpace 把纯空格也拦下来。

  3. IndexOf、Contains 等默认按当前语言文化比较,做精确匹配时可能得到意外结果。 比如判断文件路径、协议字段、关键字,应显式指定 StringComparison.Ordinal(需要忽略大小写就用 OrdinalIgnoreCase),让比较纯粹按字符数值进行,不受系统语言影响。

  4. Split 后不处理空条目,拿到一堆空字符串。 连续分隔符、末尾分隔符都会切出 "",绝大多数业务场景都应加上 StringSplitOptions.RemoveEmptyEntries,需要顺手去空格再加 TrimEntries。

  5. Substring 起始位置或长度算错,越界抛 ArgumentOutOfRangeException。 截取前先确认下标不超过 Length;C# 8 及以上优先用范围运算符 s[..5]、s[6..],写法更短也不容易数错长度。

九、小结

  1. string 是不可变的引用类型 ,所有修改类方法都返回新字符串、原串不动;== 已被重载为内容比较,判空用 IsNullOrEmpty / IsNullOrWhiteSpace。
  2. 方法按六类记:判断 (Contains、StartsWith、EndsWith)、查找 (IndexOf 系列)、截取分割 (Substring、Split、范围运算符)、修改 (Replace、Trim、Pad、ToUpper、Insert、Remove)、拼接 (Concat、Join、Format、$"")、比较(Equals、Compare、Ordinal)。
  3. 精确匹配(路径、协议、关键字)显式用 StringComparison.Ordinal,忽略大小写用 OrdinalIgnoreCase。
  4. 新语法按需用:C# 8 范围运算符、C# 11 原始字符串;循环大量拼接找 StringBuilder,规则匹配找正则。
相关推荐
小羊没烦恼!1 小时前
.NET无侵入自动化探针原理和主流实现
运维·开发语言·javascript·python·自动化·.net·1024程序员节
IT规划师1 小时前
MQTT实战 - 遗嘱消息+心跳机制,让你的设备永远不会“假在线”(七)
物联网·.net
阿松爱学习14 小时前
【Unity开发】Unity长截图功能实现
unity·c#·游戏引擎
恒锐丰科技林技术员16 小时前
EG27324 双通道驱动芯片:小封装下的高性能功率驱动方案
经验分享·嵌入式硬件·硬件工程
m0_7196408716 小时前
2026年适合课题研究的具身智能实验室建设方案有哪些可参考?
经验分享·算法
_oP_i17 小时前
Windows 11 家庭中文版 25H2
c#
unicrom_深圳市由你创科技17 小时前
电池化成曲线MES追溯:关键点提取与验证
c#
老王IT17 小时前
C#语言基础语法介绍
开发语言·c#
芯片智造18 小时前
NiFe镀层成分沿厚度方向的梯度是如何形成的?怎么消除?
经验分享