Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deferred template string interpolation

Tags:

c#

.net

In C# there is a string interpolation support like this:

$"Constant with {Value}"

which will format this string using in-scope variable Value.

But the following won't compile in current C# syntax.

Say, I have a static Dictionary<string, string> of templates:

templates = new Dictionary<string, string>
{
    { "Key1", $"{Value1}" },
    { "Key2", $"Constant with {Value2}" }
}

And then on every run of this method I want to fill in the placeholders:

public IDictionary<string, string> FillTemplate(IDictionary<string, string> placeholderValues)
{
    return templates.ToDictionary(
        t => t.Key,
        t => string.FormatByNames(t.Value, placeholderValues));
}

Is it achievable without implementing Regex parsing of those placeholders and then a replace callback on that Regex? What are the most performant options that can suit this method as being a hot path?

For example, it is easily achievable in Python:

>>> templates = { "Key1": "{Value1}", "Key2": "Constant with {Value2}" }
>>> values = { "Value1": "1", "Value2": "example 2" }
>>> result = dict(((k, v.format(**values)) for k, v in templates.items()))
>>> result
{'Key2': 'Constant with example 2', 'Key1': '1'}
>>> values2 = { "Value1": "another", "Value2": "different" }
>>> result2 = dict(((k, v.format(**values2)) for k, v in templates.items()))
>>> result2
{'Key2': 'Constant with different', 'Key1': 'another'}
like image 538
Sergey Ionov Avatar asked Apr 27 '18 22:04

Sergey Ionov


2 Answers

No, it's not possible, instead you should use String.Format.

With String format your string template would look like string template = "The temperature is {0}°C." and then to insert the value you could just:

decimal temp = 20.4m;
string s = String.Format(template, temp);

As shown in the Microsoft examples.

like image 196
Leonardo Menezes Avatar answered Sep 23 '22 06:09

Leonardo Menezes


Using an extension method that does a substitution based on regular expressions, I get a good speed up over using multiple Replace calls for each value.

Here is my extension method for expanding brace surrounded variables:

public static class ExpandExt {
    static Regex varPattern = new Regex(@"{(?<var>\w+)}", RegexOptions.Compiled);
    public static string Expand(this string src, Dictionary<string, string> vals) => varPattern.Replace(src, m => vals.TryGetValue(m.Groups[1].Value, out var v) ? v : m.Value);
}

And here is the sample code using it:

var ans = templates.ToDictionary(kv => kv.Key, kv => kv.Value.Expand(values));

Over 10,000 repeating expansions with values at 18 entries and typically only one replacement, I get 3x faster than multiple String.Replace calls.

like image 44
NetMage Avatar answered Sep 23 '22 06:09

NetMage