高效的模板人口

时间:2012-01-26 11:01:44

标签: c# string templates

假设我有一个文本模板,其中包含许多需要填充的字段:

var template = "hello {$name}. you are {$age} years old. you live in {$location}"

和要替换的IDictionary<string,string>值:

key     | value
===================
name    | spender
age     | 38
location| UK

填充模板的天真方式可能是:

var output = template;
foreach(var kvp in templValues)
{
    output = output.Replace(string.format("{{${0}}}", kvp.Key), kvp.Value);
}

但是,这似乎效率低下。还有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

您可以使用Regex.Replace(),如下所示:

var output = new Regex(@"\{\$([^}]+)\}").Replace(
    template,
    m => templValues.ContainsKey(m.Captures[1].Value)
        ? templValues[m.Captures[1].Value]
        : m.Value);

AFAIK如果您的字典是这样构建的,这也可以防止出现意外结果,因为这可能会产生"hello UK. you are 38 years old. you live in UK"以及"hello {$location}. you are 38 years old. you live in UK",因为dictionarys不会对其键进行排序:

key     | value
===================
name    | {$location}
age     | 38
location| UK

当实际需要第一个行为时,您可以多次运行正则表达式。

编辑:如果模板解析实际上是代码的时间关键部分,那么不要在那里进行模板解析。你应该考虑使用手动解析方法Sean推荐。

答案 1 :(得分:0)

如果您担心性能,一次性手动解析模板可能是最快的:

static string DictFormat(string template, IDictionary<string, string> dict) {

    const string left_delimiter = "{$";
    int left_delimiter_len = left_delimiter.Length;
    const string right_delimiter = "}";
    int right_delimiter_len = right_delimiter.Length;

    var sb = new StringBuilder();

    int end = 0;
    while (true) {

        int start = template.IndexOf(left_delimiter, end);
        if (start >= 0) {
            sb.Append(template.Substring(end, start - end));
            start += left_delimiter_len;
            end = template.IndexOf(right_delimiter, start);
            if (end >= 0) {
                string key = template.Substring(start, end - start);
                string value;
                if (dict.TryGetValue(key, out value)) {
                    sb.Append(value);
                    end += right_delimiter_len;
                }
                else
                    throw new ArgumentException(string.Format("Key not found: {0}", key), "template");
            }
            else
                throw new ArgumentException(string.Format("Key starting at {0} not properly closed.", start), "template");
        }
        else {
            sb.Append(template.Substring(end));
            return sb.ToString();
        }

    }

}

像这样使用:

const string template = "hello {$name}. you are {$age} years old. you live in {$location}";
var dict = new Dictionary<string, string> { { "name", "spender" }, { "age", "38" }, { "location", "UK" } };
string result = DictFormat(template, dict);

答案 2 :(得分:-2)

冒着愚蠢的风险,你可以写一个函数来返回你想要的字符串:

public string CreateString(string name, string age, string location)
{
  return "hello " + name + ". you are " + age + " years old. you live in " + location;
}

由于您只能在字典中存储一组值,因此以这种方式使用模板的值似乎会减少。