public

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()

  • Download Gist
StringSubstitutionExtension.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
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());
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.