Let’s face it, regular expressions are powerful and can be an immense pain in the butt to write. While crafting a regular expression to perform any input recognition is possible, it becomes exceedingly difficult when the matching rules require more complicated logic. In specific scenarios, doing an initial regular expression match is more straightforward, and then applying code logic to get the desired result.

This post will look at a straightforward example of using RegEx.Replace with the MatchEvaluator to do a two-step replacement of matched tokens.

What is RegEx.Replace?

When attempting to replace tokens in a string, many developers will reach for RegEx.Replace, which aims to take an input, a regular expression, and then returns are modified result.

Regex.Replace("test", "^test$", "success");

The example works great for simple scenarios, as it is doing token replacement. But what about the following scenario?

  1. Find all image filenames
  2. Replace the filename and extension
  3. Ignore any filename that doesn’t match a criteria.

This is possible with a regular expression but can be complex with lookahead, lookbehind, and named groups. It is not easy for most developers to pull this off. How do we get the result that we want?

Let’s look at a more readable way of solving the problem presented with MatchEvaluator.

Working with MatchEvaluator

The MatchEvaluator type is a delegate wrapper that expects a potentially mutated match result. The delegate can return any value based on the match and other logic a developer may add.

Let’s look at a solution.

using System.Text.RegularExpressions;  
  
string[] extensions = [".jpg", ".gif"];  
// lang=regex  
var pattern = @"\w*\.(\w{3,4})";  
  
var original = "test.webp, test-01.jpg and test-02.gif";  
var result = Regex.Replace(original, pattern, match =>  
{  
    var extension = Path.GetExtension(match.Value);  
    // if we don't need to do anything, return the original value  
    if (!extensions.Contains(extension)) return match.Value;  
    // convert value to a token with webp  
    var filename = Path.GetFileNameWithoutExtension(match.Value);  
    return $"{filename}-converted.webp";  
}, RegexOptions.IgnoreCase);  
  
Console.WriteLine(result);

As you can see, the MatchEvaluator delegate gets the Match. At this point, we can write custom and complex logic to transform the match.

Running the code above, returns the following result.

test.webp, test-01-converted.webp and test-02-converted.webp

Neat!

Conclusion

If you’re struggling to write that perfect RegEx for token replacement, you might find it more straightforward to do it in two steps. First, write a simple-to-understand pattern, and then use MatchEvalutor to get you to the finish line.

I hope you enjoyed this post, and thanks for reading.