我写了一个名为StringTemplate
类,允许像String.Format
格式的对象,但其名称,而不是占位符索引。这里有一个例子:正则表达式的String.Format样工具
string s = StringTemplate.Format("Hello {Name}. Today is {Date:D}, and it is {Date:T}.",
new { Name = "World", Date = DateTime.Now });
为了实现这个结果,我期待已久的占位符,并与指标取代它们。然后我将结果格式字符串传递给String.Format
。
这工作得很好,当有一倍大括号,这是一个转义序列除外。期望的行为(其是相同的String.Format
)如下所述:
- “你好{名称}”应该格式化为的 “Hello World”
- “你好{{名称}} “格式应为的 ”Hello(名称)“
- ”你好{{{名}}}“格式应为”你好{}世界“
- “你好{{{{名}}}}”格式应为“你好{{名称}}”
等等......
但我现在经常表达没有检测到转义序列,并始终把括号作为占位符之间的字符串,所以我得到的东西像“你好{0}”。
这里是我当前的正则表达式:
private static Regex _regex = new Regex(@"{(?<key>\w+)(?<format>:[^}]+)?}", RegexOptions.Compiled);
如何修改这个正则表达式忽略逃脱括号?什么似乎真的很辛苦,是我应检测根据括号的数量是否是奇数占位符,甚至......我想不出一个简单的方法,用正则表达式来做到这一点,是它甚至可能吗?
为了完整起见,这里的StringTemplate
类的完整代码:
public class StringTemplate
{
private string _template;
private static Regex _regex = new Regex(@"{(?<key>\w+)(?<format>:[^}]+)?}", RegexOptions.Compiled);
public StringTemplate(string template)
{
if (template == null)
throw new ArgumentNullException("template");
this._template = template;
}
public static implicit operator StringTemplate(string s)
{
return new StringTemplate(s);
}
public override string ToString()
{
return _template;
}
public string Format(IDictionary<string, object> values)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
Dictionary<string, int> indexes = new Dictionary<string, int>();
object[] array = new object[values.Count];
int i = 0;
foreach (string key in values.Keys)
{
array[i] = values[key];
indexes.Add(key, i++);
}
MatchEvaluator evaluator = (m) =>
{
if (m.Success)
{
string key = m.Groups["key"].Value;
string format = m.Groups["format"].Value;
int index = -1;
if (indexes.TryGetValue(key, out index))
{
return string.Format("{{{0}{1}}}", index, format);
}
}
return string.Format("{{{0}}}", m.Value);
};
string templateWithIndexes = _regex.Replace(_template, evaluator);
return string.Format(templateWithIndexes, array);
}
private static IDictionary<string, object> MakeDictionary(object obj)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (var prop in obj.GetType().GetProperties())
{
dict.Add(prop.Name, prop.GetValue(obj, null));
}
return dict;
}
public string Format(object values)
{
return Format(MakeDictionary(values));
}
public static string Format(string template, IDictionary<string, object> values)
{
return new StringTemplate(template).Format(values);
}
public static string Format(string template, object values)
{
return new StringTemplate(template).Format(values);
}
}
我最近自己走了这条路,最后建立一个解析占位符的简单状态机要比找出如何获得正则表达式更容易。另外,当我最终不得不将我的分隔符更改为方括号时(因为'FlowDocument'有一些没有很好记录的行为,而且我已经开始使用大括号),所以有很多问题我没有遇到如果我使用正则表达式,我会有。 – 2010-03-03 20:47:03
是的,我应该使用状态机来代替......但无论如何,我的代码现在可以按照我的想法工作,所以我不会改变它,除非我必须;) – 2010-03-03 22:52:48
@ThomasLevesque,你会发布你使用的代码是什么? – smartcaveman 2013-02-26 03:40:16