Menu

C# 字符串方法:Split、Replace、Contains、IndexOf、Trim、Join 等

C# 中每天都会用到的 String 方法:带多个分隔符和选项的 Split,Replace,Contains 与不区分大小写的查找,IndexOf 和 LastIndexOf,StartsWith 和 EndsWith,Trim,ToUpper 和 ToLower,PadLeft,Join,Concat,以及反转字符串。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

System.String 有几十个方法。本页介绍在实际代码中承担大部分工作的那些方法,以及重要的选项和陷阱。有一条规则适用于所有方法:字符串是不可变的,所以每个方法都会返回一个新字符串(或一个值),原字符串保持不变。单独一行写 s.Trim(); 什么也不会做;要写成 s = s.Trim();。

Split

Split 在每个分隔符处把字符串拆成一个 string[]:

输出:

3
apple
banana
cherry
red/green/ blue/yellow
INFO/started/ready

注意 " blue":Split 正好在分隔符处切开,并保留所有空格。有两个选项可以处理常见的清理工作:

输出:

5
4
c#|dotnet|linq
key=[Subject] value=[Re: Meeting: Friday]
3

RemoveEmptyEntries 会去掉长度为零的部分,但不会去掉只包含空格的部分(上面的 " " 被保留了下来)。.NET 5 新增了 StringSplitOptions.TrimEntries,两者可以组合使用:tags.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) 一次调用就能得到干净的结果。把 null 作为分隔符传入会按任意空白字符分割,这是把文本拆成单词的常用方式。

按单个 char 分割(Split(','))不需要数组。接受一个 char 加选项,或者接受单个 string 的重载从 .NET Core 2.0 起才有;上面用到的数组形式在任何地方都能用,包括 .NET Framework 和 Unity。

Replace

Replace 会替换字符或子字符串的每一个匹配项:

输出:

5551234567
555.123.4567
Cats and dogs and CATS
dogs and dogs and dogs
dogs and cats and CATS
too many spaces

带 StringComparison 参数的重载在 .NET Core 2.0 及更高版本中可用。在 .NET Framework 中,不区分大小写的替换用 Regex.Replace(text, Regex.Escape(find), replacement, RegexOptions.IgnoreCase) 完成。替换为 "" 就是删除字符的方法,少量替换时链式调用几次 Replace 也完全没问题。

Contains、IndexOf、StartsWith 和 EndsWith

这些方法用于查找。Contains 回答是或否;IndexOf 和 LastIndexOf 返回位置,没有匹配时返回 -1;StartsWith 和 EndsWith 检查开头和结尾。

输出:

True
False
True
True
8
30
28
-1
16
False
True
True

它们默认都区分大小写。Contains(string, StringComparison) 在 .NET Core 2.1 及更高版本中才有;IndexOf(...) >= 0 的写法在所有版本中都可用,这就是你在旧代码里常看到它的原因。IndexOfAny(new[] { ',', ';' }) 查找几个字符中最先出现的那个。

关于区域性:不传 StringComparison 时,StartsWith、EndsWith、IndexOf(string) 和 CompareTo 使用区分区域性的规则,而 Contains、Replace 和 IndexOf(char) 按序号比较。显式传入 StringComparison.Ordinal 或 OrdinalIgnoreCase 可以消除歧义,代码分析器也推荐这样做。

Trim、TrimStart 和 TrimEnd

Trim 去掉两端的空白字符(空格、制表符、换行符)。TrimStart 和 TrimEnd 只去掉一端。如果传入字符,就改为去掉这些字符:

输出:

[ana@example.com]
[ana@example.com \n]
[  x]
SALE
7
path/to/dir
1,234.50

Trim 只处理两端;字符串中间的空格会保留。对 "000" 调用 TrimStart('0') 会返回空字符串,所以解析数字字符串时请用 int.Parse,而不是手动去掉前导零。

ToUpper 和 ToLower

输出:

MAYA LOPEZ
maya lopez
MAYA LOPEZ
Coffee

ToUpper 和 ToLower 遵循当前区域性,所以在土耳其语中,"i".ToUpper() 是带点的大写 İ,而不是 I。对于标识符、键和文件名,请使用 ToUpperInvariant 和 ToLowerInvariant。比较时,请使用 StringComparison,而不是先转换大小写(见 字符串)。要让每个单词首字母大写,可以用 CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text),不过它不会处理已经全部大写的单词。

PadLeft 和 PadRight

补齐会添加字符,直到字符串达到指定的总宽度。它在定宽输出和给编号补零时很方便:

输出:

000042
[Tea     ]
[     Tea]
Too long already
Espresso..  2.40
Latte.....  3.60
Mocha.....  3.95

插值的对齐写法({name,-10})可以在字符串内部完成同样的工作。

Join 和 Concat

string.Join 在任意集合的元素之间插入分隔符。string.Concat 直接连接,不加分隔符:

输出:

Ana, Ben, Chloe
1 + 2 + 3
True
2026-09
AnaBenChloe
Ana, Ben and Chloe

Join 是构建分隔列表的正确方式:不需要去掉末尾多余的分隔符,而且一次就能构建出结果。它会对每个元素调用 ToString(),所以数字和对象也同样适用。

Reverse、Insert 和 Remove

没有返回字符串的 string.Reverse 方法。常用的两种做法:

输出:

desserts
desserts
True
2026/Q3-09
Hello
HelloWorld

单独调用 word.Reverse() 返回的是 IEnumerable<char>,而不是字符串;打印它只会显示一个类型名。两种方法反转的都是 UTF-16 代码单元,这会破坏由两个单元组成的字符(大多数 emoji)以及带组合重音符号的字母。

速查表

任务方法
拆分成多个部分s.Split(',')、s.Split(new[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries)
全部替换s.Replace("a", "b")
是否包含s.Contains("x")、s.Contains("x", StringComparison.OrdinalIgnoreCase)
查找位置s.IndexOf("x")、s.LastIndexOf('x')(不存在时为 -1)
是否以某内容开头或结尾s.StartsWith("x")、s.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)
去掉两端空白s.Trim()、s.TrimStart()、s.TrimEnd()
转换大小写s.ToUpper()、s.ToLowerInvariant()
补齐到指定宽度s.PadLeft(6, '0')、s.PadRight(10)
连接集合string.Join(", ", items)
取字符串的一部分s.Substring(start, length)
插入或删除s.Insert(i, "x")、s.Remove(i, count)
检查 null 或空白string.IsNullOrWhiteSpace(s)

常见问题

C# 中如何分割字符串?

text.Split(',') 返回一个 string[],包含逗号之间的各个部分。多个分隔符用数组传入(Split(new[] { ',', ';' })),字符串分隔符用 Split(new[] { ", " }, StringSplitOptions.None),StringSplitOptions.RemoveEmptyEntries 可以去掉连续分隔符产生的空部分。.NET 5 新增了 StringSplitOptions.TrimEntries,用来去掉每个部分两端的空白。

如何在忽略大小写的情况下判断一个字符串是否包含另一个字符串?

在 .NET Core 2.1 及更高版本中:text.Contains("error", StringComparison.OrdinalIgnoreCase)。.NET Framework 没有这个重载,请用 text.IndexOf("error", StringComparison.OrdinalIgnoreCase) >= 0。避免使用 text.ToLower().Contains(...),它会分配一份副本,而且在某些区域性下可能出错。

C# 中 String.Replace 会修改原字符串吗?

不会。字符串是不可变的,所以 Replace 返回一个替换了所有匹配项的新字符串,原字符串保持不变。要写成 s = s.Replace("old", "new");。它替换的是所有匹配项,而不只是第一个;如果只想替换第一个,可以用 IndexOf 找到它再重新拼接字符串,或者在 Regex 实例上调用 Replace 并把次数设为 1。

字符串没找到时 IndexOf 返回什么?

-1。任何大于等于 0 的结果都是第一个匹配项从零开始的位置。在把结果当作索引使用之前,一定要先检查 -1,因为 Substring(-1) 会抛出异常,而 Substring(-1 + 1) 会悄悄返回整个字符串。LastIndexOf 的用法相同,只是从末尾开始查找。

C# 中如何反转字符串?

把它复制到 char 数组里,反转数组,再构造一个新字符串:char[] a = s.ToCharArray(); Array.Reverse(a); string r = new string(a);。用 LINQ 的话,new string(s.Reverse().ToArray()) 效果相同。两者反转的都是 UTF-16 单元,所以 emoji 和组合重音符号可能会被打乱。

Coddy 编程语言插图

和 Coddy 一起学编程

开始