Home > Software design >  C# String replace with dictionary and Regex condition
C# String replace with dictionary and Regex condition

Time:10-05

I want to replace values of a string with a dictionary that I have but only if they comply a regex condition.

This is what I have:

string input = @"A.4 AND ([10] A.4 OR A.4) OR [10]A.4 A.5 [10]A.5";
Dictionary <string, string> dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
                                                    {"A.4", "Test"},
                                                    {"A.5", "Test2"},
                                                    };
var output = dict.Aggregate(input, (current, value) => current.Replace(value.Key, value.Value));

//current output = "Test AND ([10] Test OR Test) OR [10]Test Test2 [10]Test2"
//wished output = "Test AND ([10] A.4 OR Test) OR [10]A.4 Test2 [10]A.5"

I don't want to replace the text when there is "[10]" or "[10] " in front of the text. I think that I should use a regex or something similar but I don't know how.

CodePudding user response:

You could use regex to perform the replace operation:

var output = dict.Aggregate(input, (current, sub) => Regex.Replace(current, $@"(?<!\[10\]\s?){Regex.Escape(sub.Key)}", sub.Value));

The negative lookbehind assertion (?<!\[10\]\s?) will ensure the matched term never follows [10] or [10] .


As Panagiotis Kanavos notes you can skip the Aggregate call completely by passing a delegate that performs a dictionary lookup to Regex.Replace:

var replacePattern = $@"(?<!\[10\]\s?)(?:{string.Join('|', dict.Keys.Select(Regex.Escape))})";
var output = Regex.Replace(input, replacePattern, (m) =>  dict[m.Value]);

CodePudding user response:

Regex.Replace has an overload with a delegate that creates replacement values. If the tags have a pattern, a single regular expression can be used to match them and replace them using the dictionary values.

This regex matches tags in the form A.n where n a number:

var regex=new Regex(@"(?<!\[10\]\s?)A\.\d ");

var output=regex.Replace(input,match=>dict[match.Value]);

Console.WriteLine(output);

This produces

Test AND ([10] A.4 OR Test) OR [10]A.4 Test2 [10]A.5

(?<!...) is a negative lookbehind pattern. It matches strings that don't start with the negated pattern. (?<!\[10\]\s?) matches strings that don't start with [10] and an optional space.

  • Related