tags:

views:

178

answers:

1

There is a method

Regex.Replace(string source, string pattern, string replacement)

The last parameter supports pattern replacements such as ${groupName} and others (but I don't know the group name in the run-time).

In my case I have the dynamically created pattern like:

(?<c0>word1)|(?<c1>word2)|(?<c2>word3)

My purpose is to replace each group with the value depending on group name. For example, the word "word1" will be replaced with <span class="c0">word1</span>. This is for search results highlighting like google.

Is it possible to do this using the method above not using overloaded method with MatchEvaluator parameter?

Thanks in advance!

+1  A: 

I don't think using the ${groupname} in the manner you suggested is feasible unless I am misunderstanding the exact replacement that's being performed. The reason is the replacement string has to be constructed in such a way that it accounts for each group name. Since they are dynamically generated this doesn't make it possible. In other words how, in 1 statement, do you design a replacement string that would cover c0...cn and substitute their respective capture values? You could loop through the names but how would you keep the modified text intact to perform 1 replacement per groupname?

I do have a possible solution for you though. It still uses the MatchEvaluator overload, but with some lambda expressions and LINQ you can get this down to 1 line. However, I'll format it for clarity below. Perhaps this will fit your needs or point you in the right direction.

string text = @"The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.";
string[] searchKeywords = { "quick", "fox", "lazy" };

// build pattern based on keywords - you probably had a routine in place for this
var patternQuery = searchKeywords
                        .Select((s, i) => 
                            String.Format("(?<c{0}>{1})", i, s) +
                            (i < searchKeywords.Length - 1 ? "|" : ""))
                        .Distinct();
string pattern = String.Join("", patternQuery.ToArray());
Console.WriteLine("Dynamic pattern: {0}\n", pattern);

// use RegexOptions.IgnoreCase for case-insensitve search
Regex rx = new Regex(pattern);

// Notes:
// - Skip(1): used to ignore first groupname of 0 (entire match)
// - The idea is to use the groupname and its corresponding match. The Where
//   clause matches the pair up correctly based on the current match value
//   and returns the appropriate groupname
string result = rx.Replace(text, m => String.Format(@"<span class=""{0}"">{1}</span>", 
                    rx.GetGroupNames()
                    .Skip(1)
                    .Where(g => m.Value == m.Groups[rx.GroupNumberFromName(g)].Value)
                    .Single(),
                    m.Value));

Console.WriteLine("Original Text: {0}\n", text);
Console.WriteLine("Result: {0}", result);

Output:

Dynamic pattern: (?<c0>quick)|(?<c1>fox)|(?<c2>lazy)

Original Text: The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.

Result: The <span class="c0">quick</span> brown <span class="c1">fox</span> jumps over the <span class="c2">lazy</span> dog. The <span class="c0">quick</span> brown <span class="c1">fox</span> jumps over the <span class="c2">lazy</span> dog.
Ahmad Mageed
Thank you! I've solved my issue in such a manner. But under the "one line" term I meant something like Regex.Replace(string source, string pattern, "<span class='${groupName}'>$). But seems it is impossible in my case.One more thanks for the answer!
Alex