Find and Replace multiple strings in c# with or without regex

2.8k views Asked by At

I need some help with my code. What i am trying to do is find one string at a time in a sentence and replace the same string with a span tag.

I have achieved same with javascript but I am unsure of how to do it in C#

Code in js:

//this function takes 'buffer' as content & 
//search query (multiple string values) as replaceStrings and highlights the query

function highlitor(buffer, replaceStrings)
 {
   var highlightedText = buffer;
   for (var i = 0; i < replaceStrings.length; i++)
   {
          var exp = new RegExp("(" + replaceStrings[i] + ")", "gi");
         highlightedText = highlightedText.replace(exp, "<span class='highlight-search-text'>$1</span>");
   }

      return highlightedText;
}

For example

buffer=" This is an exciting and enhansive test"    replaceStrings=[exciting,enhace];

highlightedText="This is an <span class='highlight-text'>exciting</span> and <span class='highlight-text'>enhansive</span> test"

Thanks in advance.

2

There are 2 answers

10
Tim Schmelter On BEST ANSWER

I think you just need String.Replace in a loop:

public static string Highlitor(string text, IEnumerable<string> replaceStrings)
{
    string result = text;
    foreach(string repl in replaceStrings.Distinct())
    {
        string replWith = string.Format("<span class='highlight-text'>{0}</span>", repl);
        result = result.Replace(repl, replWith);
    }
    return result;
}

You don't need Distinct if the list doesn't contain duplicates.

UPDATE: as it seems things are much more complicated. You want to replace parts by preserving the original case when the pattern is part of the final replacement string.

Here is a modified version of my above method that uses an extended version of String.Replace:

 public static string Highlitor(string text, IEnumerable<string> replaceStrings)
{
    string result = text;
    foreach (string repl in replaceStrings.Distinct())
    {
        string replWith = string.Format("<span class='highlight-text'>{0}</span>", repl);
        result = ReplaceCaseInsensitive(result, repl, replWith, true);
    }
    return result;
}

Here is the method that replaces strings case-insensitively and supports keeping the original case:

public static string ReplaceCaseInsensitive(string original, string pattern, string replacement, bool keepOriginalCase = false)
{
    int count, position0, position1;
    count = position0 = position1 = 0;
    int replacementIndexOfPattern = replacement.IndexOf(pattern, StringComparison.OrdinalIgnoreCase);
    if (replacementIndexOfPattern == -1)
        keepOriginalCase = false; // not necessary

    int inc = (original.Length / pattern.Length) *
              (replacement.Length - pattern.Length);
    char[] chars = new char[original.Length + Math.Max(0, inc)];
    bool[] upperCaseLookup = new bool[pattern.Length];

    while ((position1 = original.IndexOf(pattern, position0, StringComparison.OrdinalIgnoreCase)) != -1)
    {             
        // first part that will not be replaced
        for (int i = position0; i < position1; ++i)
            chars[count++] = original[i];
        // remember the case of each letter in the found patter that will be replaced
        if (keepOriginalCase)
        {
            for (int i = 0; i < pattern.Length; ++i)
                upperCaseLookup[i] = Char.IsUpper(original[position1 + i]);
        }
        // The part that will be replaced:
        for (int i = 0; i < replacement.Length; ++i)
        {
            // only keep case of the relevant part of the replacement that contains the part to be replaced
            bool lookupCase = keepOriginalCase 
                && i >= replacementIndexOfPattern
                && i < replacementIndexOfPattern + pattern.Length;
            char newChar = replacement[i];
            if (lookupCase)
            {
                bool wasUpper = upperCaseLookup[i - replacementIndexOfPattern];
                bool isUpper = Char.IsUpper(newChar);
                if (wasUpper && !isUpper)
                    newChar = Char.ToUpperInvariant(newChar);
                else if (!wasUpper && isUpper)
                    newChar = Char.ToLowerInvariant(newChar);
            }
            else
            {
                newChar = replacement[i];
            }
            chars[count++] = newChar;
        }
        position0 = position1 + pattern.Length;
    }
    if (position0 == 0) 
        return original;
    // the rest
    for (int i = position0; i < original.Length; ++i)
        chars[count++] = original[i];
    return new string(chars, 0, count);
}

It's algorithm based on: Fastest C# Case Insenstive String Replace.

0
Prathamesh dhanawade On

I got the functionality as :

for (var j = 0; j < searchTermArray.Length; j++)
                    {
                        CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo;
                        int indexOfTerm = ci.IndexOf(text, searchTermArray[j], CompareOptions.IgnoreCase);

                        //dont replace if there is no search term in text
                        if(indexOfTerm!= -1)
                        {
                            string subStringToHighlight = text.Substring(indexOfTerm, searchTermArray[j].Length);

                            //replacing with span
                            string replaceWith = string.Format("<span class='highlight-search-text'>{0}</span>", subStringToHighlight);
                            text = Regex.Replace(text, searchTermArray[j], replaceWith, RegexOptions.IgnoreCase);
                        }

                    }