views:

331

answers:

3

Given the following input and regex strings:

const string inputString = "${Principal}*${Rate}*${Years}";
const string tokenMatchRegexString = @"\${([^}]+)}";

How can I replace each token (i.e. ${Principal}, ${Rate}, and ${Years}) with the return value of my 'ReplaceToken' function?

private static string ReplaceToken(string tokenString)
{
    switch (tokenString)
    {
        case "Principal":
      return GetPrincipal();
     case "Rate":
      return GetRate();
     case "Years":
      return GetYears();
     default:
      throw new NotImplementedException(String.Format("A replacment for the token '{0}' has not been implemented.", tokenString));
    }
}

private static string GetPrincipal()
{
    throw new NotImplementedException();
}

private static string GetRate()
{
    throw new NotImplementedException();
}

private static string GetYears()
{
    throw new NotImplementedException();
}
A: 

Don't reinvent the wheel. I use StringTemplate (the C# version) when doing things like this.

RichardOD
+3  A: 

Regex has an overload which takes a MatchEvaluator. The input is a Match, and it returns a string. The value of the Match in this case would be the whole token, so you could create a shim that extracts the value (you're already capturing it within your Regex) and adapts to the method you posted.

Regex.Replace(inputString,
              tokenMatchRegexString,
              match => TokenReplacement(match.Groups[1].Value));
nullptr
+3  A: 

If you really just have a small number of tokens to replace that you know ahead of time, you can use string.Replace() to just replace the tokens one by one. This simple technique can work, but it has drawbacks. It's not particularly extensible, it can result in intermediate (throwaway) strings, and it can also result in confusing code.

If you expect to have many different tokens and they have consistent matching rules, you could use Regex.Replace() which takes a MatchEvaluator delegate - essentially function which accepts a regular expression matches and returns a string to replace the match with. The benefit of using the Replace() overload that takes a MatchEvaluator is that it helps avoid the creation of intermediate strings which are then just used to replace the next match. It's also nice to reuse built-in .NET classes, rather than rolling your own.

Finally, if you have really complex match/substitution requirements, you can use libraries like StringTemplate to do more complex template expansions and match substitution.

Here's an example of using the Regex.Replace() call:

const string inputString = "${Principal}*${Rate}*${Years}";
const string tokenMatchRegexString = @"\${([^}]+)}";

var rex = new Regex( tokenMatchRegexString );
MatchEvaluator matchEval = match => TokenReplacement( match.Groups[1].Value );

rex.Replace( inputString, matchEval );
LBushkin