详情

首页手游攻略 C#中string的六大核心做法:判空、查找、截取、分割、替换一篇讲透实用指南

C#中string的六大核心做法:判空、查找、截取、分割、替换一篇讲透实用指南

佚名 2026-10-26 09:50:01

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“C#中string的六大核心做法:判空、查找、截取、分割、替换一篇讲透”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

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

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

事实 1:string 是不可变的

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

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

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

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

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

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

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

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

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

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() 再比,建议直接给比较方式:

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

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

三、查找位置类方法

3.1 IndexOf 和 LastIndexOf

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 一次给一组字符,谁先出现就得到谁的位置:

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:从指定位置截取

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 更直观:

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:按分隔符切成数组

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 及以上)
`RemoveEmptyEntriesTrimEntries`

还能够一次传多个分隔符:

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

五、修改与转换类方法

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

5.1 Replace:替换

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:去空白和补位

// 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 大小写转换

Console.WriteLine("hello".ToUpper());   // HELLO
Console.WriteLine("HELLO".ToLower()); // hello

5.4 Insert 和 Remove:插入与删除

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

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

5.5 ToCharArray:转成字符数组

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

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(静态方法)

// 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 和字符串插值

// 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 里有大量引号和反斜杠时,用三个双引号包裹的原始字符串,既不用转义,还能保留缩进:

string json = """
{
  "name": "张三",
  "age": 18
}
""";

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

七、比较类方法与 StringComparison

7.1 Equals 和 Compare

// 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,规则匹配找正则。

结合项目来看,总的来说,C#中string的六大核心方法适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

点击查看更多
推荐专题
热门阅读