C# String replace with dictionary

Viewed 31869

I have a string on which I need to do some replacements. I have a Dictionary<string, string> where I have search-replace pairs defined. I have created following extension methods to perform this operation:

public static string Replace(this string str, Dictionary<string, string> dict)
{
    StringBuilder sb = new StringBuilder(str);

    return sb.Replace(dict).ToString();
}

public static StringBuild Replace(this StringBuilder sb, 
    Dictionary<string, string> dict)
{
    foreach (KeyValuePair<string, string> replacement in dict)
    {
        sb.Replace(replacement.Key, replacement.Value);
    }

    return sb;
}

Is there a better way of doing that?

8 Answers

If the data is tokenized (i.e. "Dear $name$, as of $date$ your balance is $amount$"), then a Regex can be useful:

static readonly Regex re = new Regex(@"\$(\w+)\$", RegexOptions.Compiled);
static void Main() {
    string input = @"Dear $name$, as of $date$ your balance is $amount$";

    var args = new Dictionary<string, string>(
        StringComparer.OrdinalIgnoreCase) {
            {"name", "Mr Smith"},
            {"date", "05 Aug 2009"},
            {"amount", "GBP200"}
        };
    string output = re.Replace(input, match => args[match.Groups[1].Value]);
}

However, without something like this, I expect that your Replace loop is probably about as much as you can do, without going to extreme lengths. If it isn't tokenized, perhaps profile it; is the Replace actually a problem?

Seems reasonable to me, except for one thing: it's order-sensitive. For instance, take an input string of "$x $y" and a replacement dictionary of:

"$x" => "$y"
"$y" => "foo"

The results of the replacement are either "foo foo" or "$y foo" depending on which replacement is performed first.

You could control the ordering using a List<KeyValuePair<string, string>> instead. The alternative is to walk through the string making sure you don't consume the replacements in further replace operations. That's likely to be a lot harder though.

The correct tool for this particular task is Mustache, a simple standard logicless templating language.

There are many implementations. For this example, I'm going to use stubble:

var stubble = new StubbleBuilder().Build();
var dataHash = new Dictionary<string, Object>()
{
    {"Foo","My Foo Example"},
    {"Bar",5}
};

var output = stubble.Render(
   "Hey, watch me replace this: {{Foo}} ... with example text.  Also {{bar}} is 5"
   , dataHash
);

Why not just check whether such key exists?

  • if exists, then remove the pair, otherwise, skip this step;

  • add the same key, but now with newly desired value.

      // say, you have the following collection
      var fields = new Dictionary<string, string>();
      fields.Add("key1", "value1");
      fields.Add("key2", "value2");
      fields.Add("key3", "value3");
    
      // now, you want to add a pair "key2"/"value4"
      // or replace current value of "key2" with "value4"
      if (fields.ContainsKey("key2"))
      {
          fields.Remove("key2");
      }
      fields.Add("key2", "value4");
    
Related