views:

283

answers:

2

I am currently building this small template engine. It takes a string containing the template in parameter, and a dictionary of "tags,values" to fill in the template.

In the engine, I have no idea of the tags that will be in the template and the ones that won't.

I am currently iterating (foreach) on the dictionnary, parsing my string that I have put in a string builder, and replacing the tags in the template by their corresponding value.

Is there a more efficient/convenient way of doing this? I know the main drawback here is that the stringbuilder is parsed everytime entirely for each tag, which is quite bad...

(I am also checking, though not included in the sample, after the process that my template does not contain any tag anymore. They are all formated in the same way: @@tag@@)

//Dictionary<string, string> tagsValueCorrespondence;
//string template;

StringBuilder outputBuilder = new StringBuilder(template);
foreach (string tag in tagsValueCorrespondence.Keys)
{
    outputBuilder.Replace(tag, tagsValueCorrespondence[tag]);
}

template = outputBuilder.ToString();

Responses:

@Marc:

string template = "Some @@foobar@@ text in a @@bar@@ template";
StringDictionary data = new StringDictionary();
data.Add("foo", "value1");
data.Add("bar", "value2");
data.Add("foo2bar", "value3");

Output: "Some text in a value2 template"

instead of: "Some @@foobar@@ text in a value2 template"

+1  A: 

How about a Regex and MatchEvaluator? Like so:

string template = "Some @@Foo@@ text in a @@Bar@@ template";
StringDictionary data = new StringDictionary();
data.Add("foo", "random");
data.Add("bar", "regex");
string result = Regex.Replace(template, @"@@([^@]+)@@", delegate(Match match)
{
    string key = match.Groups[1].Value;
    return data[key];
});
Marc Gravell
Completly useless as soon has the pattern goes wrong (like another @ misplaced). I'll stick with my replace method unless somebody else has a better solution...
Edit: Actually, useless too if you have a tag like that @@foo2 bar@@. If in the template you have something like that @@foo bar@@, it is replaced by a blank space. Bad solution for error detection
Can you expand on either point? "foo bar" should still work fine... and I didn't understand your "another @ misplaced" point either. Any example?
Marc Gravell
A: 

Here is sample code you can use as starting point:

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

class Program {
    static void Main() {
        var template = " @@3@@  @@2@@ @@__@@ @@Test ZZ@@";
        var replacement = new Dictionary<string, string> {
                {"1", "Value 1"},
                {"2", "Value 2"},
                {"Test ZZ", "Value 3"},
            };
        var r = new Regex("@@(?<name>.+?)@@");
        var result = r.Replace(template, m => {
            var key = m.Groups["name"].Value;
            string val;
            if (replacement.TryGetValue(key, out val))
                return val;
            else
                return m.Value;
        });
        Console.WriteLine(result);
    }
}
Lloyd