-
字符串常用操作
字符串常用操作
概述
C#中string类型是不可变引用类型(表现类似值类型),所有修改操作都会创建新字符串。本节聚焦开发中高频使用的字符串操作,结合实例讲解核心用法及性能优化技巧。
-
字符串创建与初始化
字符串的创建方式直接影响代码可读性与效率,以下是常见场景:
1.1 基础创建
csharp
// 1. 直接赋值(推荐,自动驻留到字符串池)
string name = "Alice";
// 2. 构造函数创建(不驻留,适合动态字符数组)
char[] chars = {'H', 'e', 'l', 'l', 'o'};
string hello = new string(chars); // "Hello"
// 3. 空字符串与null的区别
string empty = ""; // 空字符串(长度0,非null)
string nullStr = null; // 未引用任何对象
逐行讲解:
直接赋值是最简洁的方式,CLR会将字面量存入字符串池(共享相同实例,节省内存);
构造函数适合从字符数组生成字符串,但不会驻留(需手动调用string.Intern加入池);
""与null不同:empty.Length ==0,nullStr.Length会抛出NullReferenceException。
1.2 逐字字符串(@符号)
处理路径、正则等含转义符的场景:
csharp
// 无需转义反斜杠或引号
string path = @"C:UsersAliceDocuments";
string regexPattern = @"^d{3}-d{4}$"; // 匹配电话号码格式
string quote = @"He said: ""I love C#"""; // 输出:He said: "I love C#"
拓展:逐字字符串保留所有字符(包括换行),适合多行文本:
csharp
string multiLine = @"Line1
Line2
Line3";
1.3 插值字符串($符号)
简化变量拼接,替代String.Format:
csharp
string name = "Bob";
int age = 25;
// 直接嵌入变量,支持表达式
string info = $"Name: {name}, Age: {age}, Next Year: {age+1}";
Console.WriteLine(info); // 输出:Name: Bob, Age:25, Next Year:26
拓展:插值字符串支持格式化(与String.Format语法一致):
csharp
decimal price = 19.99m;
string formatted = $"Price: {price:C2}"; // 货币格式,如$19.99(取决于文化)
-
字符串拼接
字符串不可变性导致频繁拼接时性能低下,需选择合适方式:
2.1 基础拼接(+号)
适合少量拼接:
csharp
string a = "Hello";
string b = "World";
string c = a + " " + b; // "Hello World"
注意:每次+号都会创建新字符串,1000次拼接会产生999个临时对象,性能差。
2.2 String.Join(批量拼接)
适合数组/集合拼接:
csharp
string[] words = {"Hello", "World", "C#"};
string joined = String.Join(" ", words); // "Hello World C#"
优势:内部优化了拼接逻辑,比+号高效,支持自定义分隔符。
2.3 StringBuilder(大量拼接)
处理100+次拼接时必用:
csharp
StringBuilder sb = new StringBuilder();
sb.Append("Hello"); // 添加字符串
sb.Append(" ");
sb.AppendLine("World"); // 添加并换行
sb.AppendFormat("Year: {0}", 2024); // 格式化添加
string result = sb.ToString(); // 转换为string
// 输出:Hello World
Year:2024
逐行讲解:
StringBuilder内部维护可变字符数组,扩容时翻倍容量(默认初始容量16);
Append/AppendLine/AppendFormat均直接修改内部数组,无临时字符串;
ToString()最终生成结果字符串。
拓展:指定初始容量减少扩容次数:
csharp
// 预计拼接1000字符,初始容量设为1000
StringBuilder sb = new StringBuilder(1000);
-
字符串分割(Split)
将字符串拆分为数组:
3.1 基础分割
csharp
string str = "apple,banana,orange";
string[] fruits = str.Split(','); // ["apple","banana","orange"]
3.2 多分割符与空项处理
csharp
string str = "apple,,banana;orange";
// 分割逗号和分号,去除空项
string[] fruits = str.Split(new char[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries);
// ["apple","banana","orange"]
参数说明:
StringSplitOptions.RemoveEmptyEntries:忽略分割后的空字符串;
StringSplitOptions.None:保留空字符串(默认)。
3.3 按长度分割(.NET 6+)
csharp
string str = "123456789";
string[] parts = str.Split(3); // ["123","456","789"](每3字符分割)
-
字符串替换(Replace)
4.1 简单替换
csharp
string str = "Hello World";
string replaced = str.Replace("World", "C#"); // "Hello C#"
string replaceChar = str.Replace('l', 'x'); // "Hexxo Worxd"
4.2 正则替换(高级场景)
需引用System.Text.RegularExpressions:
csharp
string text = "Phone: 123-456-7890";
// 将数字替换为*
string masked = Regex.Replace(text, @"d", "*"); // "Phone: ***-***-****"
// 提取数字
string numbers = Regex.Replace(text, @"[^d]", ""); // "1234567890"
拓展:正则表达式语法参考(如d匹配数字,[^d]匹配非数字)。
5. 字符串查找
5.1 包含/前缀/后缀判断
csharp
string str = "Hello World";
bool hasWorld = str.Contains("World"); // true
bool startsWithHello = str.StartsWith("Hello"); // true
bool endsWithWorld = str.EndsWith("World"); // true
5.2 子串位置查找
csharp
string str = "Hello World";
int index = str.IndexOf("o"); // 4(第一个o的位置)
int lastIndex = str.LastIndexOf("o"); // 7(最后一个o的位置)
// 从位置5开始查找
int indexFrom = str.IndexOf("o",5); //7
返回值:找到返回起始索引,否则返回-1。
5.3 提取子串
csharp
string str = "Hello World";
string sub = str.Substring(6); // "World"(从索引6开始到末尾)
string sub2 = str.Substring(0,5); // "Hello"(从0开始取5个字符)
-
字符串格式化
6.1 String.Format
经典格式化方式:
csharp
string name = "Alice";
int age = 30;
string formatted = String.Format("Name: {0}, Age: {1}", name, age);
6.2 常用格式说明符
| 符号 | 作用 | 示例 |
|---|---|---|
| C | 货币格式 | {price:C2} → $19.99 |
| D | 十进制整数(补零) | {num:D3} → 005 |
| F | 固定小数位数 | {num:F2} → 12.34 |
| Y | 日期格式 | {date:yyyy-MM-dd} → 2024-05-20 |
例子:
csharp
DateTime today = DateTime.Now;
string dateFormatted = $"Today: {today:yyyy-MM-dd HH:mm:ss}"; // 2024-05-20 14:30:00
-
大小写转换
7.1 基础转换
csharp
string str = "hello world";
string upper = str.ToUpper(); // HELLO WORLD
string lower = str.ToLower(); // hello world
7.2 标题大小写(首字母大写)
需引用System.Globalization:
csharp
string str = "hello world";
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
string title = ti.ToTitleCase(str); // Hello World
注意:仅对首字母小写的单词生效,如"HELLO"不会转为"Hello"。
8. 空白字符处理
8.1 去除首尾空白
csharp
string str = " hello world ";
string trimmed = str.Trim(); // "hello world"
string trimStart = str.TrimStart(); // "hello world "
string trimEnd = str.TrimEnd(); // " hello world"
8.2 去除指定字符
csharp
string str = "###hello###";
string trimmed = str.Trim('#'); // "hello"
string trimChars = str.Trim(new char[] {'#', 'h'}); // "ello###"
-
基础知识拓展
9.1 字符串不可变性
字符串一旦创建,任何修改操作(Replace/Substring等)都会返回新字符串,原字符串不变;
示例:string a="abc"; string b=a.Replace("a","x"); → a仍为"abc",b为"xbc"。
9.2 字符串池(String Intern Pool)
CLR维护一个池,相同字面量字符串共享实例,节省内存;
示例:string a="abc"; string b="abc"; ab → true(引用同一对象);
非字面量字符串需手动驻留:string c=new string("abc"); string d=string.Intern(c); ad → true。
9.3 字符串比较
==:重写为值比较(判断内容是否相同),但推荐用Equals明确比较方式;
Equals:支持文化/大小写忽略:
csharp
string a="Hello";
string b="hello";
bool equal = a.Equals(b, StringComparison.OrdinalIgnoreCase); // true(忽略大小写)
总结
核心原则:少量拼接用+号,批量用String.Join,大量用StringBuilder;
性能优化:避免频繁修改字符串,优先用StringBuilder;
可读性:优先用插值字符串($)替代String.Format;
高级场景:正则表达式处理复杂替换/查找。
通过本节学习,可掌握90%以上的日常字符串操作,后续需结合实际场景灵活运用。
练习
1.用StringBuilder拼接1000个"a",并输出结果;
2.将字符串"123-456-7890"转换为"1234567890";
3.格式化当前日期为"yyyy年MM月dd日 HH:mm:ss";
4.去除字符串" ###C# is awesome### "的首尾空白和#符号。
参考答案:
1.StringBuilder sb=new StringBuilder(); for(int i=0;i<1000;i++) sb.Append("a"); Console.WriteLine(sb.ToString());
2.Regex.Replace("123-456-7890", @"[^d]", "")
3.DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss")
4." ###C# is awesome### ".Trim().Trim('#')
(本节完)
下一章:集合常用操作
(深入讲解List、Dictionary等集合的核心用法)
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49379.html










