C# 字符串处理
本章将详细介绍 C# 中的字符串处理,包括字符串的创建、操作、格式化、正则表达式等,帮助你掌握文本处理的各种技巧。
字符串基础
字符串的特性
csharp
// 字符串是不可变的(Immutable)
string str1 = "Hello";
string str2 = str1;
str1 += " World"; // 创建新字符串,str1 指向新对象
Console.WriteLine($"str1: {str1}"); // "Hello World"
Console.WriteLine($"str2: {str2}"); // "Hello" (未改变)
// 字符串是引用类型
string a = "test";
string b = "test";
Console.WriteLine($"a == b: {a == b}"); // True (值相等)
Console.WriteLine($"ReferenceEquals(a, b): {ReferenceEquals(a, b)}"); // True (字符串驻留)
// 字符串长度
string message = "Hello, C#!";
Console.WriteLine($"字符串长度: {message.Length}");
// 访问字符
Console.WriteLine($"第一个字符: {message[0]}"); // 'H'
Console.WriteLine($"最后一个字符: {message[message.Length - 1]}"); // '!'字符串创建方式
csharp
// 1. 字符串字面量
string literal = "Hello World";
// 2. 逐字字符串(Verbatim String)
string path = @"C:\Users\Name\Documents\file.txt";
string multiline = @"这是一个
多行字符串
示例";
// 3. 字符串插值(String Interpolation)
string name = "Alice";
int age = 25;
string interpolated = $"姓名: {name}, 年龄: {age}";
// 4. 从字符数组创建
char[] chars = {'H', 'e', 'l', 'l', 'o'};
string fromChars = new string(chars);
// 5. 重复字符
string repeated = new string('*', 10); // "**********"
// 6. 原始字符串字面量(C# 11+)
string raw = """
这是原始字符串
可以包含 "引号" 和 \反斜杠
""";
Console.WriteLine($"字面量: {literal}");
Console.WriteLine($"路径: {path}");
Console.WriteLine($"多行:\n{multiline}");
Console.WriteLine($"插值: {interpolated}");
Console.WriteLine($"字符数组: {fromChars}");
Console.WriteLine($"重复字符: {repeated}");字符串操作方法
基本操作
csharp
string text = " Hello, C# Programming! ";
// 长度和空值检查
Console.WriteLine($"长度: {text.Length}");
Console.WriteLine($"是否为空: {string.IsNullOrEmpty(text)}");
Console.WriteLine($"是否为空或空白: {string.IsNullOrWhiteSpace(text)}");
// 去除空白字符
Console.WriteLine($"原始: '{text}'");
Console.WriteLine($"去除两端空白: '{text.Trim()}'");
Console.WriteLine($"去除左侧空白: '{text.TrimStart()}'");
Console.WriteLine($"去除右侧空白: '{text.TrimEnd()}'");
// 大小写转换
Console.WriteLine($"转大写: {text.ToUpper()}");
Console.WriteLine($"转小写: {text.ToLower()}");
Console.WriteLine($"首字母大写: {text.Trim().ToLower()}");
// 子字符串
string sample = "Hello, World!";
Console.WriteLine($"子字符串(7): '{sample.Substring(7)}'"); // "World!"
Console.WriteLine($"子字符串(7,5): '{sample.Substring(7, 5)}'"); // "World"
// 字符串连接
string first = "Hello";
string second = "World";
Console.WriteLine($"连接: {first + " " + second}");
Console.WriteLine($"Concat: {string.Concat(first, " ", second)}");
Console.WriteLine($"Join: {string.Join(" ", first, second)}");查找和替换
csharp
string text = "The quick brown fox jumps over the lazy dog";
// 查找字符和子字符串
Console.WriteLine($"包含 'fox': {text.Contains("fox")}");
Console.WriteLine($"以 'The' 开头: {text.StartsWith("The")}");
Console.WriteLine($"以 'dog' 结尾: {text.EndsWith("dog")}");
// 查找位置
int index = text.IndexOf("fox");
Console.WriteLine($"'fox' 的位置: {index}");
int lastIndex = text.LastIndexOf("the");
Console.WriteLine($"最后一个 'the' 的位置: {lastIndex}");
// 查找任意字符
int anyIndex = text.IndexOfAny(new char[] {'a', 'e', 'i', 'o', 'u'});
Console.WriteLine($"第一个元音字母位置: {anyIndex}");
// 替换
string replaced = text.Replace("fox", "cat");
Console.WriteLine($"替换后: {replaced}");
string removedSpaces = text.Replace(" ", "");
Console.WriteLine($"移除空格: {removedSpaces}");
// 大小写不敏感的操作
bool containsIgnoreCase = text.Contains("FOX", StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"忽略大小写包含 'FOX': {containsIgnoreCase}");字符串分割和连接
csharp
// 分割字符串
string csv = "apple,banana,orange,grape";
string[] fruits = csv.Split(',');
Console.WriteLine("水果列表:");
foreach (string fruit in fruits)
{
Console.WriteLine($"- {fruit}");
}
// 多个分隔符分割
string text = "apple;banana,orange:grape";
string[] parts = text.Split(new char[] {',', ';', ':'});
Console.WriteLine($"分割结果: [{string.Join(", ", parts)}]");
// 限制分割数量
string data = "name=John;age=25;city=New York;country=USA";
string[] limited = data.Split(';', 3);
Console.WriteLine($"限制分割: [{string.Join(" | ", limited)}]");
// 移除空项
string withEmpty = "a,,b,c,";
string[] withoutEmpty = withEmpty.Split(',', StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine($"移除空项: [{string.Join(", ", withoutEmpty)}]");
// 连接字符串数组
string[] words = {"Hello", "beautiful", "world"};
string joined = string.Join(" ", words);
Console.WriteLine($"连接结果: {joined}");
// 使用不同分隔符连接
string csvResult = string.Join(", ", words);
Console.WriteLine($"CSV 格式: {csvResult}");字符串格式化
复合格式化
csharp
// 基本格式化
string name = "Alice";
int age = 25;
double salary = 5000.50;
// 位置参数
string formatted1 = string.Format("姓名: {0}, 年龄: {1}, 薪资: {2}", name, age, salary);
Console.WriteLine(formatted1);
// 格式说明符
Console.WriteLine($"货币格式: {salary:C}"); // ¥5,000.50
Console.WriteLine($"百分比格式: {0.85:P}"); // 85.00%
Console.WriteLine($"固定小数点: {salary:F2}"); // 5000.50
Console.WriteLine($"数字格式: {12345:N}"); // 12,345
Console.WriteLine($"十六进制: {255:X}"); // FF
// 日期时间格式化
DateTime now = DateTime.Now;
Console.WriteLine($"完整日期时间: {now:F}");
Console.WriteLine($"短日期: {now:d}");
Console.WriteLine($"长日期: {now:D}");
Console.WriteLine($"时间: {now:T}");
Console.WriteLine($"自定义格式: {now:yyyy-MM-dd HH:mm:ss}");
// 对齐和填充
Console.WriteLine($"左对齐: |{name,-10}|");
Console.WriteLine($"右对齐: |{name,10}|");
Console.WriteLine($"数字对齐: |{age,5}|{salary,10:F2}|");字符串插值高级用法
csharp
// 基本插值
string name = "Bob";
int score = 95;
Console.WriteLine($"学生 {name} 的分数是 {score}");
// 表达式插值
Console.WriteLine($"分数等级: {(score >= 90 ? "A" : score >= 80 ? "B" : "C")}");
// 格式化插值
double price = 123.456;
Console.WriteLine($"价格: {price:C2}");
Console.WriteLine($"百分比: {0.1234:P1}");
// 对齐插值
Console.WriteLine($"|{name,-15}|{score,5}|");
// 转义大括号
Console.WriteLine($"显示大括号: {{这里是内容}}");
// 多行插值
string multilineInterpolation = $@"
学生信息:
姓名: {name}
分数: {score}
等级: {(score >= 90 ? "优秀" : "良好")}
";
Console.WriteLine(multilineInterpolation);
// 条件插值
bool showDetails = true;
Console.WriteLine($"基本信息: {name}{(showDetails ? $" (分数: {score})" : "")}");自定义格式化
csharp
// 实现 IFormattable 接口
public class Student : IFormattable
{
public string Name { get; set; }
public int Age { get; set; }
public double GPA { get; set; }
public Student(string name, int age, double gpa)
{
Name = name;
Age = age;
GPA = gpa;
}
public string ToString(string format, IFormatProvider formatProvider)
{
if (string.IsNullOrEmpty(format)) format = "G";
return format.ToUpperInvariant() switch
{
"G" => $"{Name} ({Age}岁)",
"F" => $"姓名: {Name}, 年龄: {Age}, GPA: {GPA:F2}",
"S" => Name,
"A" => Age.ToString(),
"GPA" => GPA.ToString("F2"),
_ => throw new FormatException($"格式 '{format}' 不受支持")
};
}
public override string ToString() => ToString("G", null);
}
// 使用自定义格式化
static void CustomFormattingDemo()
{
var student = new Student("Charlie", 20, 3.75);
Console.WriteLine($"默认格式: {student}");
Console.WriteLine($"完整格式: {student:F}");
Console.WriteLine($"仅姓名: {student:S}");
Console.WriteLine($"仅年龄: {student:A}");
Console.WriteLine($"仅GPA: {student:GPA}");
}StringBuilder 类
基本用法
csharp
using System.Text;
// StringBuilder 用于高效的字符串构建
StringBuilder sb = new StringBuilder();
// 添加内容
sb.Append("Hello");
sb.Append(" ");
sb.Append("World");
sb.AppendLine("!"); // 添加并换行
// 插入内容
sb.Insert(5, " Beautiful");
// 替换内容
sb.Replace("World", "C#");
Console.WriteLine($"StringBuilder 结果: {sb.ToString()}");
Console.WriteLine($"长度: {sb.Length}");
Console.WriteLine($"容量: {sb.Capacity}");
// 清空内容
sb.Clear();
Console.WriteLine($"清空后长度: {sb.Length}");性能比较
csharp
using System.Diagnostics;
static void StringPerformanceComparison()
{
const int iterations = 10000;
var stopwatch = new Stopwatch();
// 使用字符串连接
stopwatch.Start();
string result1 = "";
for (int i = 0; i < iterations; i++)
{
result1 += "a";
}
stopwatch.Stop();
Console.WriteLine($"字符串连接耗时: {stopwatch.ElapsedMilliseconds} ms");
// 使用 StringBuilder
stopwatch.Restart();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++)
{
sb.Append("a");
}
string result2 = sb.ToString();
stopwatch.Stop();
Console.WriteLine($"StringBuilder 耗时: {stopwatch.ElapsedMilliseconds} ms");
// 预设容量的 StringBuilder
stopwatch.Restart();
StringBuilder sbWithCapacity = new StringBuilder(iterations);
for (int i = 0; i < iterations; i++)
{
sbWithCapacity.Append("a");
}
string result3 = sbWithCapacity.ToString();
stopwatch.Stop();
Console.WriteLine($"预设容量 StringBuilder 耗时: {stopwatch.ElapsedMilliseconds} ms");
}StringBuilder 高级用法
csharp
using System.Text;
static void StringBuilderAdvanced()
{
// 创建带初始容量的 StringBuilder
StringBuilder sb = new StringBuilder(100);
// 链式调用
sb.Append("姓名: ")
.Append("Alice")
.AppendLine()
.Append("年龄: ")
.Append(25)
.AppendLine()
.Append("城市: ")
.Append("北京");
Console.WriteLine("链式调用结果:");
Console.WriteLine(sb.ToString());
// 格式化添加
sb.Clear();
sb.AppendFormat("今天是 {0:yyyy年MM月dd日}", DateTime.Now);
sb.AppendLine();
sb.AppendFormat("温度: {0:F1}°C", 25.6);
Console.WriteLine("\n格式化结果:");
Console.WriteLine(sb.ToString());
// 移除字符
sb.Remove(0, 3); // 移除前3个字符
Console.WriteLine($"\n移除前3个字符: {sb.ToString()}");
// 设置长度
sb.Length = 10; // 截断到10个字符
Console.WriteLine($"截断到10个字符: {sb.ToString()}");
}正则表达式
基本正则表达式
csharp
using System.Text.RegularExpressions;
static void BasicRegexDemo()
{
string text = "联系电话: 138-1234-5678, 邮箱: user@example.com";
// 匹配手机号码
string phonePattern = @"\d{3}-\d{4}-\d{4}";
Match phoneMatch = Regex.Match(text, phonePattern);
if (phoneMatch.Success)
{
Console.WriteLine($"找到手机号: {phoneMatch.Value}");
}
// 匹配邮箱地址
string emailPattern = @"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b";
Match emailMatch = Regex.Match(text, emailPattern);
if (emailMatch.Success)
{
Console.WriteLine($"找到邮箱: {emailMatch.Value}");
}
// 查找所有数字
string numberPattern = @"\d+";
MatchCollection numberMatches = Regex.Matches(text, numberPattern);
Console.WriteLine("找到的数字:");
foreach (Match match in numberMatches)
{
Console.WriteLine($"- {match.Value}");
}
// 验证格式
string[] emails = {
"valid@example.com",
"invalid.email",
"another@test.org",
"bad@email"
};
Console.WriteLine("\n邮箱验证:");
foreach (string email in emails)
{
bool isValid = Regex.IsMatch(email, emailPattern);
Console.WriteLine($"{email}: {(isValid ? "有效" : "无效")}");
}
}正则表达式替换和分组
csharp
using System.Text.RegularExpressions;
static void RegexReplaceAndGroups()
{
// 替换操作
string text = "今天的日期是 2023-12-25,明天是 2023-12-26";
// 简单替换
string replaced = Regex.Replace(text, @"\d{4}-\d{2}-\d{2}", "YYYY-MM-DD");
Console.WriteLine($"替换日期: {replaced}");
// 使用分组进行复杂替换
string datePattern = @"(\d{4})-(\d{2})-(\d{2})";
string dateReplaced = Regex.Replace(text, datePattern, "$3/$2/$1");
Console.WriteLine($"日期格式转换: {dateReplaced}");
// 分组捕获
string logEntry = "2023-12-25 14:30:15 [ERROR] 数据库连接失败";
string logPattern = @"(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)";
Match logMatch = Regex.Match(logEntry, logPattern);
if (logMatch.Success)
{
Console.WriteLine("\n日志解析:");
Console.WriteLine($"日期: {logMatch.Groups[1].Value}");
Console.WriteLine($"时间: {logMatch.Groups[2].Value}");
Console.WriteLine($"级别: {logMatch.Groups[3].Value}");
Console.WriteLine($"消息: {logMatch.Groups[4].Value}");
}
// 命名分组
string namedPattern = @"(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<message>.+)";
Match namedMatch = Regex.Match(logEntry, namedPattern);
if (namedMatch.Success)
{
Console.WriteLine("\n命名分组解析:");
Console.WriteLine($"日期: {namedMatch.Groups["date"].Value}");
Console.WriteLine($"时间: {namedMatch.Groups["time"].Value}");
Console.WriteLine($"级别: {namedMatch.Groups["level"].Value}");
Console.WriteLine($"消息: {namedMatch.Groups["message"].Value}");
}
}常用正则表达式模式
csharp
using System.Text.RegularExpressions;
static class RegexPatterns
{
// 常用正则表达式模式
public static readonly string Email = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
public static readonly string Phone = @"^1[3-9]\d{9}$"; // 中国手机号
public static readonly string IdCard = @"^\d{17}[\dXx]$"; // 身份证号
public static readonly string Url = @"^https?://[^\s/$.?#].[^\s]*$";
public static readonly string IPv4 = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
public static readonly string Password = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$";
public static bool ValidateEmail(string email)
{
return Regex.IsMatch(email, Email);
}
public static bool ValidatePhone(string phone)
{
return Regex.IsMatch(phone, Phone);
}
public static bool ValidatePassword(string password)
{
return Regex.IsMatch(password, Password);
}
public static string ExtractNumbers(string text)
{
return Regex.Replace(text, @"[^\d]", "");
}
public static string[] SplitByWhitespace(string text)
{
return Regex.Split(text, @"\s+");
}
}
static void ValidationDemo()
{
Console.WriteLine("=== 数据验证演示 ===");
// 邮箱验证
string[] emails = {
"user@example.com",
"invalid.email",
"test@domain.co.uk",
"bad@"
};
Console.WriteLine("邮箱验证:");
foreach (string email in emails)
{
bool isValid = RegexPatterns.ValidateEmail(email);
Console.WriteLine($"{email}: {(isValid ? "✓" : "✗")}");
}
// 手机号验证
string[] phones = {
"13812345678",
"12345678901",
"15987654321",
"1234567890"
};
Console.WriteLine("\n手机号验证:");
foreach (string phone in phones)
{
bool isValid = RegexPatterns.ValidatePhone(phone);
Console.WriteLine($"{phone}: {(isValid ? "✓" : "✗")}");
}
// 密码强度验证
string[] passwords = {
"Password123!",
"password",
"PASSWORD123",
"Pass123",
"MySecure@Pass1"
};
Console.WriteLine("\n密码强度验证 (需要大小写字母、数字、特殊字符,至少8位):");
foreach (string password in passwords)
{
bool isValid = RegexPatterns.ValidatePassword(password);
Console.WriteLine($"{password}: {(isValid ? "✓" : "✗")}");
}
}实践示例
示例 1:文本分析工具
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
class TextAnalyzer
{
public class AnalysisResult
{
public int CharacterCount { get; set; }
public int WordCount { get; set; }
public int SentenceCount { get; set; }
public int ParagraphCount { get; set; }
public Dictionary<string, int> WordFrequency { get; set; }
public double AverageWordsPerSentence { get; set; }
public string MostFrequentWord { get; set; }
}
public static AnalysisResult AnalyzeText(string text)
{
if (string.IsNullOrWhiteSpace(text))
return new AnalysisResult();
var result = new AnalysisResult();
// 字符数(不包括空白字符)
result.CharacterCount = text.Count(c => !char.IsWhiteSpace(c));
// 单词数
string[] words = Regex.Split(text.ToLower(), @"\W+")
.Where(w => !string.IsNullOrEmpty(w))
.ToArray();
result.WordCount = words.Length;
// 句子数
result.SentenceCount = Regex.Matches(text, @"[.!?]+").Count;
// 段落数
result.ParagraphCount = text.Split(new string[] { "\n\n", "\r\n\r\n" },
StringSplitOptions.RemoveEmptyEntries).Length;
// 词频统计
result.WordFrequency = words.GroupBy(w => w)
.ToDictionary(g => g.Key, g => g.Count());
// 平均每句话的单词数
result.AverageWordsPerSentence = result.SentenceCount > 0
? (double)result.WordCount / result.SentenceCount
: 0;
// 最频繁的单词
result.MostFrequentWord = result.WordFrequency.Any()
? result.WordFrequency.OrderByDescending(kvp => kvp.Value).First().Key
: "";
return result;
}
public static void DisplayAnalysis(AnalysisResult result)
{
Console.WriteLine("=== 文本分析结果 ===");
Console.WriteLine($"字符数: {result.CharacterCount}");
Console.WriteLine($"单词数: {result.WordCount}");
Console.WriteLine($"句子数: {result.SentenceCount}");
Console.WriteLine($"段落数: {result.ParagraphCount}");
Console.WriteLine($"平均每句单词数: {result.AverageWordsPerSentence:F1}");
Console.WriteLine($"最频繁单词: {result.MostFrequentWord}");
Console.WriteLine("\n词频统计 (前10个):");
var topWords = result.WordFrequency
.OrderByDescending(kvp => kvp.Value)
.Take(10);
foreach (var word in topWords)
{
Console.WriteLine($" {word.Key}: {word.Value}次");
}
}
static void Main()
{
string sampleText = @"
C# 是一种现代的、通用的、面向对象的编程语言。
它由微软开发,是 .NET 平台的主要语言之一。
C# 语言简洁、类型安全、面向对象。
C# 广泛应用于桌面应用、Web 开发、移动应用等领域。
学习 C# 可以帮助开发者构建各种类型的应用程序。
";
var result = AnalyzeText(sampleText);
DisplayAnalysis(result);
}
}示例 2:日志解析器
csharp
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
class LogEntry
{
public DateTime Timestamp { get; set; }
public string Level { get; set; }
public string Source { get; set; }
public string Message { get; set; }
public override string ToString()
{
return $"[{Timestamp:yyyy-MM-dd HH:mm:ss}] {Level} - {Source}: {Message}";
}
}
class LogParser
{
private static readonly Regex LogPattern = new Regex(
@"(?<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(?<level>\w+)\]\s+(?<source>\w+):\s*(?<message>.*)",
RegexOptions.Compiled);
public static List<LogEntry> ParseLogs(string[] logLines)
{
var entries = new List<LogEntry>();
foreach (string line in logLines)
{
if (string.IsNullOrWhiteSpace(line))
continue;
var match = LogPattern.Match(line);
if (match.Success)
{
var entry = new LogEntry
{
Timestamp = DateTime.Parse(match.Groups["timestamp"].Value),
Level = match.Groups["level"].Value,
Source = match.Groups["source"].Value,
Message = match.Groups["message"].Value
};
entries.Add(entry);
}
}
return entries;
}
public static void AnalyzeLogs(List<LogEntry> entries)
{
Console.WriteLine("=== 日志分析 ===");
Console.WriteLine($"总日志条数: {entries.Count}");
// 按级别统计
var levelStats = entries.GroupBy(e => e.Level)
.ToDictionary(g => g.Key, g => g.Count());
Console.WriteLine("\n按级别统计:");
foreach (var stat in levelStats.OrderByDescending(kvp => kvp.Value))
{
Console.WriteLine($" {stat.Key}: {stat.Value} 条");
}
// 按来源统计
var sourceStats = entries.GroupBy(e => e.Source)
.ToDictionary(g => g.Key, g => g.Count());
Console.WriteLine("\n按来源统计:");
foreach (var stat in sourceStats.OrderByDescending(kvp => kvp.Value))
{
Console.WriteLine($" {stat.Key}: {stat.Value} 条");
}
// 错误日志
var errors = entries.Where(e => e.Level.Equals("ERROR", StringComparison.OrdinalIgnoreCase))
.ToList();
if (errors.Any())
{
Console.WriteLine($"\n错误日志 ({errors.Count} 条):");
foreach (var error in errors.Take(5)) // 显示前5条
{
Console.WriteLine($" {error}");
}
}
// 时间范围
if (entries.Any())
{
var earliest = entries.Min(e => e.Timestamp);
var latest = entries.Max(e => e.Timestamp);
Console.WriteLine($"\n时间范围: {earliest:yyyy-MM-dd HH:mm:ss} 到 {latest:yyyy-MM-dd HH:mm:ss}");
}
}
static void Main()
{
string[] sampleLogs = {
"2023-12-25 10:30:15 [INFO] Application: 系统启动成功",
"2023-12-25 10:30:16 [DEBUG] Database: 连接数据库",
"2023-12-25 10:30:17 [INFO] Authentication: 用户登录成功",
"2023-12-25 10:35:22 [WARN] Cache: 缓存命中率较低",
"2023-12-25 10:40:33 [ERROR] Database: 数据库连接超时",
"2023-12-25 10:41:15 [INFO] Application: 重新连接数据库",
"2023-12-25 10:42:00 [ERROR] Payment: 支付处理失败",
"2023-12-25 10:45:30 [INFO] Cleanup: 清理临时文件完成"
};
var entries = ParseLogs(sampleLogs);
AnalyzeLogs(entries);
}
}示例 3:模板引擎
csharp
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
class SimpleTemplateEngine
{
private static readonly Regex VariablePattern = new Regex(
@"\{\{(\w+)\}\}",
RegexOptions.Compiled);
private static readonly Regex LoopPattern = new Regex(
@"\{\{\s*for\s+(\w+)\s+in\s+(\w+)\s*\}\}(.*?)\{\{\s*endfor\s*\}\}",
RegexOptions.Compiled | RegexOptions.Singleline);
public static string Render(string template, Dictionary<string, object> data)
{
string result = template;
// 处理循环
result = ProcessLoops(result, data);
// 处理变量替换
result = ProcessVariables(result, data);
return result;
}
private static string ProcessLoops(string template, Dictionary<string, object> data)
{
return LoopPattern.Replace(template, match =>
{
string itemVar = match.Groups[1].Value;
string listVar = match.Groups[2].Value;
string loopTemplate = match.Groups[3].Value;
if (!data.ContainsKey(listVar) || !(data[listVar] is IEnumerable<object> list))
return "";
var result = new System.Text.StringBuilder();
foreach (var item in list)
{
var loopData = new Dictionary<string, object>(data)
{
[itemVar] = item
};
string processedLoop = ProcessVariables(loopTemplate, loopData);
result.Append(processedLoop);
}
return result.ToString();
});
}
private static string ProcessVariables(string template, Dictionary<string, object> data)
{
return VariablePattern.Replace(template, match =>
{
string varName = match.Groups[1].Value;
if (data.ContainsKey(varName))
{
return data[varName]?.ToString() ?? "";
}
return match.Value; // 保持原样如果变量不存在
});
}
static void Main()
{
// 简单变量替换
string simpleTemplate = "Hello, {{name}}! Today is {{date}}.";
var simpleData = new Dictionary<string, object>
{
["name"] = "Alice",
["date"] = DateTime.Now.ToString("yyyy-MM-dd")
};
Console.WriteLine("简单模板:");
Console.WriteLine(Render(simpleTemplate, simpleData));
// 循环模板
string loopTemplate = @"
购物清单:
{{for item in items}}
- {{item}}
{{endfor}}
总共 {{count}} 项商品。
";
var loopData = new Dictionary<string, object>
{
["items"] = new List<object> { "苹果", "香蕉", "牛奶", "面包" },
["count"] = 4
};
Console.WriteLine("\n循环模板:");
Console.WriteLine(Render(loopTemplate, loopData));
// 复杂模板
string complexTemplate = @"
用户报告 - {{reportDate}}
用户: {{user.name}} ({{user.email}})
注册日期: {{user.registerDate}}
最近订单:
{{for order in orders}}
订单 #{{order.id}} - {{order.date}} - ¥{{order.amount}}
{{endfor}}
总订单数: {{orderCount}}
总金额: ¥{{totalAmount}}
";
var complexData = new Dictionary<string, object>
{
["reportDate"] = DateTime.Now.ToString("yyyy-MM-dd"),
["user"] = new Dictionary<string, object>
{
["name"] = "张三",
["email"] = "zhangsan@example.com",
["registerDate"] = "2023-01-15"
},
["orders"] = new List<object>
{
new Dictionary<string, object> { ["id"] = "001", ["date"] = "2023-12-20", ["amount"] = "299.00" },
new Dictionary<string, object> { ["id"] = "002", ["date"] = "2023-12-22", ["amount"] = "156.50" },
new Dictionary<string, object> { ["id"] = "003", ["date"] = "2023-12-24", ["amount"] = "89.90" }
},
["orderCount"] = 3,
["totalAmount"] = "545.40"
};
Console.WriteLine("\n复杂模板:");
Console.WriteLine(Render(complexTemplate, complexData));
}
}本章小结
本章详细介绍了 C# 中的字符串处理:
关键要点:
- 字符串特性:不可变性、引用类型、字符串驻留
- 基本操作:创建、访问、修改、查找、替换、分割
- 格式化:复合格式化、字符串插值、自定义格式化
- StringBuilder:高效的字符串构建,适用于大量字符串操作
- 正则表达式:强大的模式匹配和文本处理工具
最佳实践:
- 大量字符串操作时使用 StringBuilder
- 使用字符串插值提高代码可读性
- 合理使用正则表达式进行复杂文本处理
- 注意字符串比较时的大小写和文化敏感性
- 验证用户输入时使用正则表达式
性能考虑:
- 避免在循环中进行大量字符串连接
- 预设 StringBuilder 的初始容量
- 编译常用的正则表达式模式
- 使用 StringComparison 枚举指定比较方式
下一步: 在下一章中,我们将学习面向对象编程的基础——类和对象。