一个非常简单的基于正则表达式的解决方案。支持\n-style 单字符转义序列和{Name}-style 命名变量。
来源
class Template
{
/// <summary>Map of replacements for characters prefixed with a backward slash</summary>
private static readonly Dictionary<char, string> EscapeChars
= new Dictionary<char, string>
{
['r'] = "\r",
['n'] = "\n",
['\\'] = "\\",
['{'] = "{",
};
/// <summary>Pre-compiled regular expression used during the rendering process</summary>
private static readonly Regex RenderExpr = new Regex(@"\\.|{([a-z0-9_.\-]+)}",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>Template string associated with the instance</summary>
public string TemplateString { get; }
/// <summary>Create a new instance with the specified template string</summary>
/// <param name="TemplateString">Template string associated with the instance</param>
public Template(string TemplateString)
{
if (TemplateString == null) {
throw new ArgumentNullException(nameof(TemplateString));
}
this.TemplateString = TemplateString;
}
/// <summary>Render the template using the supplied variable values</summary>
/// <param name="Variables">Variables that can be substituted in the template string</param>
/// <returns>The rendered template string</returns>
public string Render(Dictionary<string, object> Variables)
{
return Render(this.TemplateString, Variables);
}
/// <summary>Render the supplied template string using the supplied variable values</summary>
/// <param name="TemplateString">The template string to render</param>
/// <param name="Variables">Variables that can be substituted in the template string</param>
/// <returns>The rendered template string</returns>
public static string Render(string TemplateString, Dictionary<string, object> Variables)
{
if (TemplateString == null) {
throw new ArgumentNullException(nameof(TemplateString));
}
return RenderExpr.Replace(TemplateString, Match => {
switch (Match.Value[0]) {
case '\\':
if (EscapeChars.ContainsKey(Match.Value[1])) {
return EscapeChars[Match.Value[1]];
}
break;
case '{':
if (Variables.ContainsKey(Match.Groups[1].Value)) {
return Variables[Match.Groups[1].Value].ToString();
}
break;
}
return string.Empty;
});
}
}
用法
var tplStr1 = @"Hello {Name},\nNice to meet you!";
var tplStr2 = @"This {Type} \{contains} \\ some things \\n that shouldn't be rendered";
var variableValues = new Dictionary<string, object>
{
["Name"] = "Bob",
["Type"] = "string",
};
Console.Write(Template.Render(tplStr1, variableValues));
// Hello Bob,
// Nice to meet you!
var template = new Template(tplStr2);
Console.Write(template.Render(variableValues));
// This string {contains} \ some things \n that shouldn't be rendered
注意事项
- 我只定义了
\n、\r、\\ 和\{ 转义序列并对其进行了硬编码。您可以轻松地添加更多内容或使它们可由消费者定义。
- 我已将变量名设置为不区分大小写,因为这样的事情通常会呈现给最终用户/非程序员,我个人认为在该用例中区分大小写没有意义 - 它只是一个更多的事情他们可能会出错并打电话给你抱怨(一般来说,如果你认为你需要区分大小写的符号名称,你真正需要的是更好的符号名称)。要使它们区分大小写,只需删除
RegexOptions.IgnoreCase 标志即可。
- 我从结果字符串中去除了无效的变量名和转义序列。要使它们保持不变,请在
Regex.Replace 回调的末尾返回 Match.Value 而不是空字符串。您也可以抛出异常。
- 我使用了
{var} 语法,但这可能会干扰本机内插字符串语法。如果您想在代码中以字符串文字定义模板,建议将变量分隔符更改为例如%var% (regex \\.|%([a-z0-9_.\-]+)%) 或您选择的其他更适合用例的语法。