十四、字符、字符串和文本处理(Characters, Strings, and Text Handling)
✅ 第14章:字符、字符串和文本处理(Characters, Strings, and Text Handling)
📌 一、System.Char(字符)
.NET中的字符为System.Char,本质是 16 位Unicode字符(UTF-16编码单元)- 每个字符支持 字符分类、大小写转换、数字检测 等操作:
char c = 'A';
Console.WriteLine(char.IsLetter(c)); // true
Console.WriteLine(char.ToLower(c)); // 'a'
⚠️ 注意:某些字符如 emoji 是由两个 UTF-16 单元组成(称为 surrogate pairs)。
📘 二、System.String(字符串)
System.String是 不可变(immutable) 的引用类型,一旦创建就不能修改- 字符串的每次“修改”都会生成新实例(拼接、截取等)
CLR知道String类型中定义的字段如何布局,会直接访问这些字段。但为了获得这种件能和直接访问的好处,String 只能是密封类。
设计原因:
- 安全(线程安全)
- 效率(字符串池复用)
- 可哈希(字符串哈希值稳定)
System.Environment类型定义了只读 NewLine 属性. 应用程序在MicrosoftWindows 上运行时,该属性返回由回车符和换行符 构成的字符串。 NewLine 属性对平台敏感,会根据底层平台来返回恰当 的字符串。 例如,如果将公共语言基础结构(CLI)移植到 UNIX 系统, NewLine 属性将返回由单字符\n构成的宇符串。 以下才是定义上述字符 串的正确方式,它在任何平台上都能正确工作: String s= "Hi"+ Environment.NewLine + "there.";
⚙️ 三、高效构造字符串:StringBuilder
- 当需要频繁修改字符串时,推荐使用:
var sb = new StringBuilder();
sb.Append("Hello");
sb.Append(" World");
Console.WriteLine(sb.ToString()); // Hello World
| 操作 | 推荐类型 |
|---|---|
| 读取 + 不变 | string |
| 频繁拼接/修改 | StringBuilder |
StringBuilder 只有以下两种情况才会分配新对象。
- 动态构造字符串,其长度超过了设置的"容量" 。
- 调用StringBuilder 的 ToString 方法。
🔄 四、ToString 与 Parse:对象与字符串的双向转换
✅ ToString()
- 任何类型都可覆盖
ToString(),提供格式化输出
DateTime dt = DateTime.Now;
Console.WriteLine(dt.ToString("yyyy-MM-dd"));
✅ Parse()
- 将字符串转换为对象
int x = int.Parse("123");
DateTime d = DateTime.Parse("2024-01-01");
⚠️ 建议使用 TryParse(),避免格式异常:
if (int.TryParse("abc", out int result))
Console.WriteLine(result);
else
Console.WriteLine("Invalid number");
🌐 五、编码:字符 <--> 字节转换
.NET 中最常用的编码器有:
| 编码器 | 特点 |
|---|---|
UTF8Encoding |
推荐默认,节省空间,兼容性强 |
UnicodeEncoding |
UTF-16,每个字符两个字节 |
ASCIIEncoding |
只支持 0–127 的 ASCII 字符,已过时 |
示例:
string s = "你好";
byte[] utf8 = Encoding.UTF8.GetBytes(s);
string back = Encoding.UTF8.GetString(utf8);
🔐 六、安全字符串(SecureString)
SecureString将字符串内容加密存储在内存中,防止明文字符串被转储泄露
⚠️ 仅在极安全场景使用,如登录凭据处理,且仅限 .NET Framework,.NET Core 中已弃用
📊 Mermaid 图:字符串操作流程图
🎯 七、C# string 类型高阶技巧
1️⃣ 避免隐性堆分配:用 string.Concat() 替代 +
string s1 = "Hello";
string s2 = "World";
string result = string.Concat(s1, s2); // ✅ 性能更优
string r2 = s1 + s2; // ❌ 编译器生成额外中间字符串,可能堆分配
✅ Concat 不创建中间对象链,效率更高(尤其在循环中)
2️⃣ 频繁拼接用 StringBuilder,但小拼接用 string.Create(.NET Core+)
string s = string.Create(10, 'X', (span, state) =>
{
for (int i = 0; i < span.Length; i++) span[i] = state;
});
Console.WriteLine(s); // "XXXXXXXXXX"
✅ 避免堆分配 + 原地构造,用于高频字符串生成或性能敏感路径
3️⃣ 了解字符串池机制(String Interning)
string a = "test";
string b = "te" + "st"; // 编译期拼接,自动驻留
Console.WriteLine(object.ReferenceEquals(a, b)); // true
使用 string.Intern(str) 可手动将运行时字符串驻留到池中,节省内存。
⚠️ 不当使用会导致永久内存泄漏(字符串池常驻内存)
4️⃣ Span 处理子字符串,无堆分配
ReadOnlySpan<char> span = "Hello World".AsSpan();
ReadOnlySpan<char> word = span.Slice(6, 5);
Console.WriteLine(word.ToString()); // "World"
✅ Span<T> 是结构体,不分配堆内存,可用于高性能文本解析(如 JSON/XML Parser)
5️⃣ Use string.Equals(a, b, StringComparison.Ordinal),避免文化陷阱
string a = "straße";
string b = "STRASSE";
// ❌ 默认是 CurrentCultureIgnoreCase,结果为 true
Console.WriteLine(a.Equals(b, StringComparison.CurrentCultureIgnoreCase));
// ✅ 推荐
Console.WriteLine(a.Equals(b, StringComparison.OrdinalIgnoreCase)); // false
✅ 面试点:字符串比较若为 ID、Key、Token 一类值,必须用 Ordinal 比较!
6️⃣ 字符串只读,但可通过 unsafe 修改(黑魔法,慎用)
string s = "hello";
unsafe
{
fixed (char* p = s)
{
p[0] = 'H';
}
}
Console.WriteLine(s); // "Hello"
⚠️ 会破坏字符串不可变性,影响安全性,仅供学习参考或极端性能压榨。
7️⃣ Regex Cache:避免重复创建正则表达式
static readonly Regex _emailRegex = new Regex(@"^\S+@\S+\.\S+$", RegexOptions.Compiled);
✅ 使用 RegexOptions.Compiled 提升性能 + 缓存静态实例,避免内存泄漏与GC压力
🧠 总结表格
| 技巧 | 说明 |
|---|---|
string.Concat |
拼接性能优于 + |
string.Create |
原地构造,0分配 |
string.Intern |
控制池驻留,减少重复常量 |
Span<char> |
不创建新字符串的子串处理 |
StringComparison.Ordinal |
高性能 + 避免文化问题 |
unsafe 改写字符 |
不推荐,仅限特殊场景 |
Regex 编译 + 缓存 |
高性能模式匹配方式 |
🧠 面试题精选
1️⃣ 为什么 string 是 immutable?性能不是更差吗?
✅ 为了线程安全、哈希可用性、共享字符串池;若频繁操作,应用 StringBuilder 替代。
2️⃣ 使用 StringBuilder 能节省多少内存?
✅ 具体数值依赖操作次数,但在大规模拼接场景中可减少数百倍的分配与垃圾回收。
3️⃣ 如何安全地从字符串转换为数值?
✅ 使用 TryParse(),可避免格式异常,提升健壮性。
4️⃣ UTF-8 与 UTF-16 在 .NET 中如何选择?
✅ 推荐默认使用 Encoding.UTF8,节省空间;除非与平台交互需要定长才使用 UTF-16。
5️⃣ 什么是 surrogate pair?为啥重要?
✅ UTF-16 中部分字符(如 emoji、部分亚洲文字)需两个 char 组合,开发时需谨慎处理索引与长度。
✅ 总结表格
| 模块 | 要点 |
|---|---|
char |
单个 UTF-16 单元表示字符 |
string |
不可变,适合只读处理 |
StringBuilder |
高效拼接,适合频繁修改 |
ToString / Parse |
对象 ↔ 字符串转换方式 |
| 编码 | UTF-8 推荐、ASCII 避免 |
| 安全字符串 | 特定安全场景使用 SecureString |
作者:世纪末的魔术师
出处:https://www.cnblogs.com/Firepad-magic/
Unity最受欢迎插件推荐:点击查看
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号