65.9K
CodeProject is changing. Read more.
Home

Advanced Text-Replace with Regex.Matchevaluator

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (7 votes)

Jul 23, 2016

CPOL

1 min read

viewsIcon

10322

This is an alternative for "C# Sprintf-Lite"

Introduction

Let me demonstrate a powerful, but quite unknown overload of Regex.Replace().
I won't go into Regex-Programming in Detail - hopefully you are familiar with that, or you'll find a good Resource on the Internet.

The demand is - as stated here - to convert format-strings for the C-sprintf(format, <arglist>) - Function to format-strings, which are applicable to  the .NET- string.Format(format, <arglist>)-Function.

For instance, the C formatstring:

"%s shoots a %s at you for %d damage!"

is to convert to:

"{0} shoots a {1} at you for {2} damage!"

Code

using System.Text.RegularExpressions;
//...
private static Regex _rgxPrint2Format = new Regex("%[sd]");

private static string Sprint(string format,params object[] args) {
   var counter = 0;
   MatchEvaluator match2String = mt => string.Concat("{", counter++, "}");
   return string.Format(_rgxPrint2Format.Replace(format, match2String), args);
}

You see: the problem is solved in 4 lines of code. To understand the solution, there is to understand, what a Matchevaluator is - see its definition in ObjectBrowser (<-follow the link, if you don't know the OB):

public delegate string MatchEvaluator(RegularExpressions.Match match)

It is a Delegate of a function, which converts a Regex.Match to a string.

In the code above, line#7, the function, targeted by the delegate is directly noted as anonymous Function within the same line, and it replaces the Match by "{<counter>}", then increments counter - that's all.
Next Line I pass my converter to _rgxPrint2Format.Replace(,) which applies it to each occurring match.
Means: The Regex finds the matches, the converter converts them to .NET-like placeholders, and therefore the .NET- string.Format() - method can apply the converted format-instructions to the args.

Code Usage

private void Test() {
   var output =  Sprint("%s %s", "hello", "World");
   Console.WriteLine(output);

   output = Sprint("%s", "hello", "World");
   Console.WriteLine(output);

   output = Sprint("%s %d", "hello", "World", 23);
   Console.WriteLine(output);

   output = Sprint("%s %s %d", "hello", "World", 23);

   Console.WriteLine(output);

   output = Sprint("%s shoots a %s at you for %d damage!", 
                   "lakedoo2310", "fireball", 99);
   Console.WriteLine(output);
}

The output is as expected:

hello World
hello
hello World
hello World 23
lakedoo2310 shoots a fireball at you for 99 damage!