Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Created March 31, 2011 16:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindplay-dk/896724 to your computer and use it in GitHub Desktop.
Save mindplay-dk/896724 to your computer and use it in GitHub Desktop.
A static class that allows you to use name/value pairs from an dictionary to substitute string-representations of object values - this extension complements String.Format()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Mindplay.Extensions
{
/// <summary>
/// This extension provides an alternative to <see cref="String.Format"/> allowing the
/// use of an <see cref="IDictionary{String,Object}"/> to replace named (rather than
/// numbered) tokens in a string template.
///
/// Usage is Similar to that of String.Format(), but the string templates use names
/// instead of numbers when referencing the values to substitute - and the input is
/// a dictionary rather than an array.
///
/// The following unit test provides a demonstration of how to use this extension:
///
/// <code>
/// var replacements = new Dictionary<String, object>()
/// {
/// { "date1", new DateTime(2009, 7, 1) },
/// { "hiTime", new TimeSpan(14, 17, 32) },
/// { "hiTemp", 62.1m },
/// { "loTime", new TimeSpan(3, 16, 10) },
/// { "loTemp", 54.8m }
/// };
///
/// var template =
/// "Temperature on {date1:d}:\n{hiTime,11}: {hiTemp} degrees (hi)\n{loTime,11}: {loTemp} degrees (lo)";
///
/// var expected = "Temperature on 7/1/2009:\n 14:17:32: 62.1 degrees (hi)\n 03:16:10: 54.8 degrees (lo)";
///
/// var result = template.Subtitute(replacements);
///
/// Assert.IsTrue(
/// result == expected,
/// "string template mismatch:\n" + result + "\nexpected:\n" + expected);
/// </code>
///
/// You may contrast this example with the reference example provided for String.Format():
///
/// http://msdn.microsoft.com/en-us/library/1ksz8yb7.aspx
/// </summary>
public static class StringSubstitutionExtension
{
private static readonly Regex Pattern = new Regex(@"(?<!\{)\{(\w+)([^\}]*)\}");
/// <summary>
/// Replaces the format item in a specified string with the string representation of a corresponding object in a specified dictionary.
/// </summary>
public static String Subtitute(this String template, IDictionary<String,Object> dictionary)
{
return Subtitute(template, null, dictionary);
}
/// <summary>
/// Replaces the format item in a specified string with the string representation of a corresponding object in a specified dictionary.
/// A specified parameter supplies culture-specific formatting information.
/// </summary>
public static String Subtitute(this String template, IFormatProvider formatProvider, IDictionary<String,Object> dictionary)
{
var map = new Dictionary<String,int>();
var list = new List<Object>();
var format = Pattern.Replace(
template,
match =>
{
var name = match.Groups[1].Captures[0].Value;
if (!map.ContainsKey(name))
{
map[name] = map.Count;
list.Add(dictionary.ContainsKey(name) ? dictionary[name] : null);
}
return "{" + map[name] + match.Groups[2].Captures[0].Value + "}";
}
);
return formatProvider == null
?
String.Format(format, list.ToArray())
:
String.Format(formatProvider, format, list.ToArray());
}
}
}
@mindplay-dk
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment