Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User based string template

Tags:

c#

I have a string template that the user chooses, I need to take that template and fill in the requested information.

string templateString = "%author% - %title% (%year%)";

I could do .Contains() and .Replace(), however the template could have a large amount of inputs or a small amount such as:

string templateString = "%author% - %publisher% - %isbn% - %asin% - %title% (%year%)";

So to do .Contains() and .Replace() for every option that the user can choose seems inefficient, what I am hoping to do is find a better way of populating the templateString with the requested information. Any help would be greatly appreciated. This would be used on thousands of items.

The program itself takes however many files the user inputs (ebooks, some of us have thousands of them), and it renames every ebook based off the individual user's template, filling the information with metadata scraped from the ebook.

like image 767
Cardon Fry Avatar asked Sep 26 '26 13:09

Cardon Fry


2 Answers

I posted this somewhere else but it looks like it would be a good approach in your case (I've done this myself as well). Basically you use a regular expression replace with a match evaluator callback:

regex = new Regex(@"\%(?<value>.*?)\%", 
    RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);

string replacedText = regex.Replace(<text>, 
    new MatchEvaluator(this.EvaluateMatchCallback));

Then your callback would look like this:

private string EvaluateMatchCallback(Match match) {
    string templateInsert = match.Groups["value"].Value;
    // or whatever
    string replacedText = GetReplacementTextBasedOnTemplateValue(templateInsert);
    return replacedText;
}

Where GetReplacementTextBasedOnTemplateValue is a method that would return whatever value corresponds to the placeholder that was matched by the regex.

like image 61
kprobst Avatar answered Sep 28 '26 02:09

kprobst


I've done this in the past. Instead of using .Contains I simply call .Replace(pattern, replacement) for every available option. In a typical user-oriented (eg. data display/entry) app, the user will NEVER notice any slowdown.

You really should veryify that you have a performance issue before trying to optimize for performance. You're most likely wasting your time.

TEST DATA: Using the test code below you can see that replacing 10 values in 25,000 "books" takes under 2 seconds, most of which is caused by writing to the console (runtime drops to under 160ms if you remove the Console.WriteLine() and just add the books to a List<String>()). Seems pretty acceptable to me.

String template = @"%index%.  %title% - %author% [%isbn%] - %year%";
            Dictionary<String, String> values = new Dictionary<String, String> { { "title", "A day in the life of..." }, { "author", "Joe S. Schmoe" }, { "year", "1945" }, { "isbn", "987-987-987-987-987" }, { "one", "1" }, { "two", "2" }, { "three", "3" }, { "four", "4" }, { "five", "5" }, { "six", "6" }, { "seven", "7" } };
            String output = string.Empty;
            Stopwatch watch = new Stopwatch();

            watch.Start();
            for (Int32 index = 0; index < 25000; index++) {
                output = template;
                foreach (String key in values.Keys) {
                    output = output.Replace("%" + key + "%", values[key]);
                }
                output = output.Replace("%index%", index.ToString());
                Console.WriteLine(output);
            }
            watch.Stop();

            Console.WriteLine("Elapsed time (ms): " + watch.ElapsedMilliseconds.ToString());
like image 20
Sam Axe Avatar answered Sep 28 '26 03:09

Sam Axe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!