title: format string template with named parameters to literal c#
body: <p>I have an application that creates string templates with named variables. This is done in accordance to the logging guide for <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.2#log-message-template" rel="nofollow noreferrer">ASP.NET Core</a></p>
  
  <p>Now I find myself wanting to deliver these strings through the API itself as well, but this time with all the parameters filled in.</p>
  
  <p>Basicly I'd want to use:</p>
  
  <pre><code>var template = "ID {ID} not found";
  var para = new object[] {"value"};
  String.Format(template, para);
  </code></pre>
  
  <p>However this gives an invalid input string.
  Ofcourse I also cannot guarantee that somebody din't make a string template the 'classic' way with indexes.</p>
  
  <pre><code>var template2 = "ID {0} not found";
  </code></pre>
  
  <p>Is there a new way of formatting strings that I'm missing or are we supposed to work around this ?</p>
  
  <p>I do not want to rework the existing code base to use numbers or use the $"...{para}" syntax. As this would lose information when it is being logged.</p>
  
  <p>I'm guessing I could do a regex search and see if there's a '{0}' or a named parameter, and replace the named with indexes before formatting. But I wanted to know if there are some easier/cleaner ways of doing this.</p>
  
  <h1>Update - regex solution:</h1>
  
  <p>Bellow is the current work-around I've made using regex </p>
  
  <pre><code>public static class StringUtils
      {
          public static string Format(string template, params object[] para)
          {
              var match = Regex.Match(template, @"\{@?\w+}");
              if (!match.Success) return template;
  
              if (int.TryParse(match.Value.Substring(1, match.Value.Length - 2), out int n))
                  return string.Format(template, para);
              else
              {
                  var list = new List&lt;string&gt;();
                  var nextStartIndex = 0;
                  var i = 0;
                  while (match.Success)
                  {
                      if (match.Index &gt; nextStartIndex)
                          list.Add(template.Substring(nextStartIndex , match.Index - nextStartIndex) + $"{{{i}}}");
                      else
                          list.Add($"{{{i}}}");
  
                      nextStartIndex = match.Index + match.Value.Length;
  
                      match = match.NextMatch();
                      i++;
                  }
  
                  return string.Format(string.Join("",list.ToArray()), para);
              }
          }
      }
  </code></pre>