Mortalus
Mortalus

Reputation: 10712

Replace multiple Regex Matches each with a different replacement

I have a string that may or may not have multiple matches for a designated pattern.

Each needs to be replaced.

I have this code:

var pattern = @"\$\$\@[a-zA-Z0-9_]*\b";
var stringVariableMatches = Regex.Matches(strValue, pattern);
var sb = new StringBuilder(strValue);

foreach (Match stringVarMatch in stringVariableMatches)
{
    var stringReplacment = variablesDictionary[stringVarMatch.Value];
    sb.Remove(stringVarMatch.Index, stringVarMatch.Length)
            .Insert(stringVarMatch.Index, stringReplacment);
}

return sb.ToString();

The problem is that when I have several matches the first is replaced and the starting index of the other is changed so that in some cases after the replacement when the string is shorten I get an index out of bounds..

I know I could just use Regex.Replace for each match but this sound performance heavy and wanted to see if someone could point a different solution to substitute multiple matches each with a different string.

Upvotes: 10

Views: 14206

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627607

Use a Match evaluator inside the Regex.Replace:

var pattern = @"\$\$\@[a-zA-Z0-9_]*\b";
var stringVariableMatches = Regex.Replace(strValue, pattern, 
        m => variablesDictionary[m.Value]);

The Regex.Replace method will perform global replacements, i.e. will search for all non-overlapping substrings that match the indicated pattern, and will replace each found match value with the variablesDictionary[m.Value].

Note that it might be a good idea to check if the key exists in the dictionary.

See a C# demo:

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Linq;
public class Test
{
    public static void Main()
    {
        var variablesDictionary = new Dictionary<string, string>();
        variablesDictionary.Add("$$@Key", "Value");
        var pattern = @"\$\$@[a-zA-Z0-9_]+\b";
        var stringVariableMatches = Regex.Replace("$$@Unknown and $$@Key", pattern, 
                m => variablesDictionary.ContainsKey(m.Value) ? variablesDictionary[m.Value] : m.Value);
        Console.WriteLine(stringVariableMatches);
    }
}

Output: $$@Unknown and Value.

Upvotes: 24

Related Questions