在 C# 编程中,字符串处理是日常开发中不可或缺的一部分。无论是处理用户输入、文件读取,还是与外部系统交互,都离不开对字符串的各种操作。本文将全面介绍 C# 中丰富的字符串处理方法,结合代码示例,帮助你深入理解并掌握这些实用技巧。
Length
属性Length
属性用于获取字符串中字符的个数,且不包括末尾的空字符。这是一个非常基础且常用的属性,在很多场景下都能发挥重要作用。
string str = "Hello";
Console.WriteLine(str.Length); // 输出 5
ToLower()
和 ToUpper()
在处理字符串时,有时需要将字符串统一转换为大写或小写形式,以方便进行比较或其他操作。ToLower()
方法将字符串转换为小写形式,ToUpper()
方法则将其转换为大写形式。
string str = "Hello";
Console.WriteLine(str.ToLower()); // 输出 "hello"
Console.WriteLine(str.ToUpper()); // 输出 "HELLO"
Substring(int startIndex, int length)
当需要从一个较长的字符串中提取特定部分时,Substring
方法就派上用场了。它允许你从指定的索引开始,截取指定长度的子字符串。
string str = "Hello World";
Console.WriteLine(str.Substring(6, 5)); // 输出 "World"
Remove(int startIndex, int length)
Remove
方法用于从指定索引开始移除指定长度的字符。这在需要对字符串进行清理或修改时非常有用。
string str = "Hello World";
Console.WriteLine(str.Remove(6, 5)); // 输出 "Hello "
另外,Remove(int startIndex)
方法可以从指定索引开始移除字符串的剩余部分。
string str = "Hello World";
Console.WriteLine(str.Remove(6)); // 输出 "Hello "
Replace(string oldValue, string newValue)
Replace
方法可以将字符串中的指定字符或子字符串替换为新的内容。这在处理文本替换、数据清洗等场景中经常使用。
string str = "Hello World";
Console.WriteLine(str.Replace('o', '0')); // 输出 "Hell0 W0rld"
Console.WriteLine(str.Replace("World", "C#")); // 输出 "Hello C#"
Split(char[] separator, StringSplitOptions options)
Split
方法根据指定的分隔符将字符串拆分成多个子字符串,并返回一个字符串数组。StringSplitOptions
枚举可以控制是否移除空元素。
string str = "Hello,World,C#";
string[] parts = str.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string part in parts)
{
Console.WriteLine(part); // 输出 "Hello" "World" "C#"
}
IndexOf
和 LastIndexOf
IndexOf
方法用于查找指定字符或子字符串在字符串中第一次出现的位置,而 LastIndexOf
方法则查找其最后一次出现的位置。如果未找到,这两个方法都会返回 -1。
string str = "Hello World";
Console.WriteLine(str.IndexOf('W')); // 输出 6
Console.WriteLine(str.IndexOf("World")); // 输出 6
string str2 = "abc abc abc";
Console.WriteLine(str2.LastIndexOf('a')); // 输出 9(最后一个 'a' 的位置)
Console.WriteLine(str2.LastIndexOf("abc")); // 输出 9(最后一个 "abc" 的位置)
Trim()
、TrimStart()
和 TrimEnd()
在处理用户输入或读取文件时,字符串的开头或结尾可能会包含空白字符(如空格、制表符和换行符)。Trim
方法可以移除字符串两端的空白字符,TrimStart
方法移除开头的空白字符,TrimEnd
方法移除结尾的空白字符。
string str = " Hello World ";
Console.WriteLine(str.Trim()); // 输出 "Hello World"
Console.WriteLine(str.TrimStart()); // 输出 "Hello World "
Console.WriteLine(str.TrimEnd()); // 输出 " Hello World"
Contains(string value)
Contains
方法用于判断字符串是否包含指定的子字符串。如果包含,返回 true
;否则返回 false
。
string str = "Hello World";
Console.WriteLine(str.Contains("World")); // 输出 True
StartsWith(string value)
和 EndsWith(string value)
StartsWith
方法判断字符串是否以指定的子字符串开始,EndsWith
方法判断字符串是否以指定的子字符串结束。这在验证文件扩展名、URL 前缀等场景中非常有用。
string str = "Hello World";
Console.WriteLine(str.StartsWith("Hello")); // 输出 True
Console.WriteLine(str.EndsWith("World")); // 输出 True
PadLeft(int totalWidth, char paddingChar)
和 PadRight(int totalWidth, char paddingChar)
PadLeft
和 PadRight
方法可以在字符串的左侧或右侧填充指定的字符,直到达到指定的总宽度。这在格式化输出、生成固定长度的字符串等场景中很实用。
string str = "123";
Console.WriteLine(str.PadLeft(5, '*')); // 输出 "**123"(左侧填充2个'*')
Console.WriteLine(str.PadRight(5, '*')); // 输出 "123**"(右侧填充2个'*')
Join(string separator, params string[] values)
和 Concat(params string[] values)
Join
方法将多个字符串连接成一个字符串,并使用指定的分隔符分隔它们;Concat
方法则直接将多个字符串连接起来。
string[] words = { "Hello", "World", "C#" };
string sentence = string.Join(", ", words);
Console.WriteLine(sentence); // 输出 "Hello, World, C#"
string result = string.Concat("Hello", " ", "World");
Console.WriteLine(result); // 输出 "Hello World"
Format(string format, params object[] args)
和字符串插值Format
方法可以将指定的参数插入到格式字符串中,实现字符串的格式化。从 C# 6.0 开始,还引入了字符串插值的语法,使用 $
符号和大括号 {}
来嵌入变量或表达式,使代码更加简洁易读。
string name = "John";
int age = 30;
string formattedString = string.Format("Name: {0}, Age: {1}", name, age);
Console.WriteLine(formattedString); // 输出 "Name: John, Age: 30"
int age2 = 30;
string name2 = "Alice";
string message = $"My name is {name2} and I am {age2} years old.";
Console.WriteLine(message); // 输出 "My name is Alice and I am 30 years old."
IsNullOrEmpty(string value)
和 IsNullOrWhiteSpace(string value)
IsNullOrEmpty
方法用于判断字符串是否为空或 null
,IsNullOrWhiteSpace
方法则判断字符串是否为空、null
或仅包含空白字符。在处理用户输入时,这两个方法可以帮助我们进行有效的验证。
string str1 = null;
Console.WriteLine(string.IsNullOrEmpty(str1)); // 输出 True
string str2 = " ";
Console.WriteLine(string.IsNullOrWhiteSpace(str2)); // 输出 True
CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
CopyTo
方法将字符串中的字符复制到指定的字符数组中。需要注意的是,超出字符串长度的部分不会被复制,保持默认值。
char[] charArray = new char[5];
string str = "Hello";
str.CopyTo(0, charArray, 0, 5);
Console.WriteLine(new string(charArray)); // 输出 "Hello"
IndexOfAny(char[] anyOf)
和 LastIndexOfAny(char[] anyOf
IndexOfAny
方法查找字符数组中字符在字符串中第一次出现的位置,LastIndexOfAny
方法查找其最后一次出现的位置。
string str = "Hello World";
char[] chars = { 'o', 'W' };
Console.WriteLine(str.IndexOfAny(chars)); // 输出 4('o'的位置)
Console.WriteLine(str.LastIndexOfAny(chars)); // 输出 6('W'的位置)
Insert(int startIndex, string value)
Insert
方法可以在指定索引处插入一个字符串,实现对字符串的动态修改。
string str = "Hello";
Console.WriteLine(str.Insert(5, " World")); // 输出 "Hello World"
// 验证邮箱格式
bool IsValidEmail(string email) =>
Regex.IsMatch(email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
// 替换所有数字
string sanitized = Regex.Replace("abc123def456", @"\d", ""); // "abcdef"
技巧:使用RegexOptions.Compiled
预编译正则表达式提升性能。
// 文化敏感比较(默认)
bool equals1 = "Müller".Equals("mueller", StringComparison.CurrentCulture);
// 二进制比较(区分大小写)
bool equals2 = "Müller".Equals("MÜLLER", StringComparison.Ordinal);
// 不区分大小写和重音符号
bool equals3 = "café".Equals("CAFE",
StringComparison.OrdinalIgnoreCase |
StringComparison.InvariantCultureIgnoreCase);
// 低效方式:每次拼接生成新对象
string result = "";
for (int i = 0; i < 1000; i++) result += i;
// 高效方式:使用StringBuilder
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++) sb.Append(i);
string optimized = sb.ToString();
// 字符串转字节数组
byte[] bytes = Encoding.UTF8.GetBytes("Hello");
// 字节数组转字符串
string text = Encoding.UTF8.GetString(bytes);
// 方法1:使用ToCharArray和Reverse
string reversed = new string("Hello".ToCharArray().Reverse().ToArray());
// 方法2:使用LINQ
string reversed2 = string.Join("", "Hello".Reverse());
// 空值合并运算符
string username = user?.Name ?? "Guest";
// 空值条件调用
int? length = user?.Name?.Length;
// 数字格式化
decimal amount = 1234.5678m;
string formatted = amount.ToString("C2"); // $1,234.57
// 日期格式化
DateTime now = DateTime.Now;
string date = now.ToString("yyyy-MM-dd HH:mm:ss");
// 使用StringIntern防止重复字符串
string key1 = "Hello";
string key2 = string.Intern("Hello"); // 共享同一内存地址
// 只读内存Span
ReadOnlySpan span = "Hello".AsSpan();
// 按多个分隔符分割
string[] parts = "apple;banana,orange".Split(
new[] { ';', ',' },
StringSplitOptions.TrimEntries);
// 按固定长度分割
IEnumerable SplitFixedLength(string input, int length)
{
for (int i = 0; i < input.Length; i += length)
yield return input.Substring(i, Math.Min(length, input.Length - i));
}
// 反模式:每次循环创建新字符串
foreach (var item in items)
message += item.ToString();
// 推荐:使用StringBuilder
var sb = new StringBuilder();
foreach (var item in items)
sb.Append(item.ToString());
message = sb.ToString();
public static class Constants
{
public static readonly string Success = "Operation succeeded";
public static readonly string Error = "An error occurred";
}
private static readonly Regex EmailRegex =
new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$", RegexOptions.Compiled);
分类 | 方法名 | 说明 |
---|---|---|
基础操作 | Length | 获取字符个数 |
ToCharArray | 转换为字符数组 | |
修改操作 | Substring, Insert, Remove, Replace | 子串截取、插入、删除、替换 |
查找操作 | IndexOf, LastIndexOf, Contains | 查找位置、是否包含 |
转换操作 | ToLower, ToUpper, Trim | 大小写转换、空白修剪 |
组合操作 | Join, Concat, Split | 字符串拼接与分割 |
格式化 | Format, 插值 | 字符串格式化 |
高级操作 | Regex, StringBuilder, Encoding | 正则表达式、高效拼接、编码转换 |
安全检查 | IsNullOrEmpty, IsNullOrWhiteSpace | 空值与空白检查 |
DateTime.ParseExact
方法将日志中的时间戳按照指定的格式进行解析,并处理可能的格式错误。\n
替换为当前环境的换行符,方便后续显示。// 定义日志条目类,用于存储解析后的日志信息
public class LogEntry
{
// 日志的时间戳
public DateTime Timestamp { get; set; }
// 日志的级别,如 INFO、ERROR 等
public string Level { get; set; }
// 日志的具体消息内容
public string Message { get; set; }
}
// 日志解析器类,负责将日志字符串解析为 LogEntry 对象
public class LogParser
{
// 定义日期时间的格式,用于解析日志中的时间戳
private const string DateFormat = "yyyy-MM-dd HH:mm:ss";
// 解析日志行的方法,接收一个日志字符串作为输入,返回解析后的 LogEntry 对象
public LogEntry Parse(string logLine)
{
// 思路:首先检查输入的日志行是否为空或仅包含空白字符,如果是则抛出异常,避免后续处理时出现错误
if (string.IsNullOrWhiteSpace(logLine))
{
// 抛出 ArgumentException 异常,提示输入的日志行无效
throw new ArgumentException("输入的日志行不能为空或仅包含空白字符。", nameof(logLine));
}
// 思路:使用 Split 方法将日志行按 '|' 字符分割成多个部分,并去除每个部分前后的空白字符
string[] parts = logLine.Split('|', StringSplitOptions.TrimEntries);
// 思路:检查分割后的部分数量是否符合预期,如果不符合则抛出异常,确保日志格式正确
if (parts.Length != 3)
{
// 抛出 ArgumentException 异常,提示日志行格式不正确
throw new ArgumentException("日志行格式不正确,预期包含 3 个部分,用 '|' 分隔。", nameof(logLine));
}
// 尝试解析时间戳
DateTime timestamp;
try
{
// 思路:使用 DateTime.ParseExact 方法将分割后的第一部分按照指定的日期时间格式进行解析
// CultureInfo.InvariantCulture 确保解析时不依赖于当前系统的区域设置
timestamp = DateTime.ParseExact(parts[0], DateFormat, CultureInfo.InvariantCulture);
}
catch (FormatException)
{
// 若解析失败,抛出 ArgumentException 异常,提示时间戳格式不正确
throw new ArgumentException($"时间戳格式不正确,预期格式为 '{DateFormat}'。", nameof(logLine));
}
// 思路:将分割后的第二部分转换为大写,作为日志级别
string level = parts[1].ToUpper();
// 思路:将分割后的第三部分中的 "\n" 替换为当前环境的换行符
string message = parts[2].Replace("\\n", Environment.NewLine);
// 创建一个新的 LogEntry 对象,并将解析得到的时间戳、日志级别和消息内容赋值给对应的属性
return new LogEntry
{
Timestamp = timestamp,
Level = level,
Message = message
};
}
}
// 以下是一个简单的测试类,用于演示 LogParser 的使用
class Program
{
static void Main()
{
// 示例日志行
string logLine = "2024-01-01 12:00:00|INFO|这是一条日志消息\\n第二行";
// 创建 LogParser 实例
LogParser parser = new LogParser();
try
{
// 调用 Parse 方法解析日志行
LogEntry entry = parser.Parse(logLine);
// 输出解析后的日志信息
Console.WriteLine($"时间戳: {entry.Timestamp}");
Console.WriteLine($"日志级别: {entry.Level}");
Console.WriteLine($"日志消息: {entry.Message}");
}
catch (ArgumentException ex)
{
// 捕获并输出解析过程中可能抛出的异常信息
Console.WriteLine($"解析日志时出错: {ex.Message}");
}
}
}