Note that there are some explanatory texts on larger screens.

plurals
  1. PORegular expression for String.Format-like utility
    text
    copied!<p>I'm writing a class called <code>StringTemplate</code>, which allows to format objects like with <code>String.Format</code>, but with names instead of indexes for placeholders. Here's an example :</p> <pre><code>string s = StringTemplate.Format("Hello {Name}. Today is {Date:D}, and it is {Date:T}.", new { Name = "World", Date = DateTime.Now }); </code></pre> <p>To achieve this result, I look for placeholders and replace them with indexes. I then pass the resulting format string to <code>String.Format</code>.</p> <p>This works fine, except when there are doubled braces, which are an escape sequence. The desired behavior (which is the same as <code>String.Format</code>) is described below :</p> <ul> <li><em>"Hello {Name}"</em> should be formatted as <em>"Hello World"</em></li> <li><em>"Hello {{Name}}"</em> should be formatted as <em>"Hello {Name}"</em></li> <li><em>"Hello {{{Name}}}"</em> should be formatted as <em>"Hello {World}"</em></li> <li><em>"Hello {{{{Name}}}}"</em> should be formatted as <em>"Hello {{Name}}"</em></li> </ul> <p>And so on...</p> <p>But my current regular expression doesn't detect the escape sequence, and always considers the substring between brackets as a placeholder, so I get things like <em>"Hello {0}"</em>.</p> <p>Here's my current regular expression :</p> <pre><code>private static Regex _regex = new Regex(@"{(?&lt;key&gt;\w+)(?&lt;format&gt;:[^}]+)?}", RegexOptions.Compiled); </code></pre> <p><strong>How can I modify this regular expression to ignore escaped braces ?</strong> What seems really hard is that I should detect placeholders depending on whether the number of brackets is odd or even... I can't think of a simple way to do it with a regular expression, is it even possible ?</p> <hr> <p>For completeness, here's the full code of the <code>StringTemplate</code> class :</p> <pre><code>public class StringTemplate { private string _template; private static Regex _regex = new Regex(@"{(?&lt;key&gt;\w+)(?&lt;format&gt;:[^}]+)?}", 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&lt;string, object&gt; values) { if (values == null) { throw new ArgumentNullException("values"); } Dictionary&lt;string, int&gt; indexes = new Dictionary&lt;string, int&gt;(); 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) =&gt; { 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&lt;string, object&gt; MakeDictionary(object obj) { Dictionary&lt;string, object&gt; dict = new Dictionary&lt;string, object&gt;(); 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&lt;string, object&gt; values) { return new StringTemplate(template).Format(values); } public static string Format(string template, object values) { return new StringTemplate(template).Format(values); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload