Monday, July 13, 2009

Case Insensitive String Replace

A few weeks ago a colleague asked me if there was a case insensitive string replacement function in .NET.

As far as I know there isn’t, but there is a case insensitive overload for the String.IndexOf which allows you to easily write your own. Here’s a sample one;

/// <summary>
///
Performs either a case sensitive or case insensitive search and replace on the specified string.
/// </summary>
/// <param name="sourceString">
The string containing the data to be replaced.</param>
/// <param name="searchString">
The substring to find (and replace).</param>
/// <param name="replaceString">
The string to replace searchString with.</param>
/// <param name="caseSensitive">
A boolean indicating whether or not this replace is case sensitive.</param>
/// <returns>
A new string where all instances of the substring specified by searchString have been replaced with the one provided by replaceString.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "string")]
public static string Replace(string sourceString, string searchString, string replaceString, bool caseSensitive)
{
if (sourceString == null) throw new ArgumentNullException("sourceString");
if (searchString == null) throw new ArgumentNullException("searchString");
if (String.IsNullOrEmpty(searchString)) throw new ArgumentException("searchString cannot be an empty string.", "searchString");
if (replaceString == null) throw new ArgumentNullException("replaceString");

StringBuilder retVal = new StringBuilder(sourceString.Length);

int ptr = 0, lastPtr = 0;

while (ptr >= 0)
{
ptr = sourceString.IndexOf(searchString, ptr, caseSensitive ? StringComparison.InvariantCulture : StringComparison.OrdinalIgnoreCase);

int strLength = ptr - lastPtr;
if (strLength > 0 ptr == 0)
{
if (ptr > 0)
retVal.Append(sourceString.Substring(lastPtr, strLength));

retVal.Append(replaceString);
ptr += searchString.Length;
}
else
break
;

lastPtr = ptr;
}

if (lastPtr >= 0) //Append the piece of the string left after the last occurrence of searchString, if any.
retVal.Append(sourceString.Substring(lastPtr));

return retVal.ToString();
}







6 comments:

  1. If you're using VB.NET, there's an easier way

    newStr = Replace(oldStr, searchText, newText, , , CompareMethod.Text)

    If you're using C#, just add a reference to Microsoft.VisualBasic.dll, and then use the above method from the Microsoft.VisualBasic namespace. You may need to pass default values to the optional parameters.

    ReplyDelete
  2. Thanks for that MD.

    That is true, and I have done that myself in some projects so I could use other VB functions, but it's always felt kind of icky to me.

    It's not so much referencing a DLL with VisualBasic in the name, since it's just a .Net assembly and it ships with the runtime, but more than I'm loading in a hell of a lot of other 'stuff' with that assembly that I don't neccesarily want... and that increases memory footprint etc. For the sake of a single string handling function, I'd still use my own unless there was a perf reason or something not to.

    However, it's still a good tip as other people may not feel the same way, and the VB version probably has other benefits (particularly when it comes to globalisation etc).

    Thanks again.

    ReplyDelete
  3. Thanks for replying

    I also do not feel good when using legacy VB6 string processing functions (e.g. Left, Right, Mid, etc.) unless they serve useful purposes. In my opinion, their names are just confusing. At least they should have been named StrLeft, StrRight, etc. to make more sense when MS migrated them to VB.NET. They did so for the file I/O Open function, it was renamed FileOpen... 'Replace' is among those few examples where I feel comfortable using.

    Btw, how do I modify your function to perform a case-insensitive replace and return the original case-insensitive match(es) in the original string? For example, given the string

    "Microsoft Visual Studio 2010"

    when user searches for "VISUAL", I want to change to:

    "Microsoft Visual Studio 2010"

    e.g. add ... (for search highlight) and maintain original case. For this I need to know the original match ("Visual" and not "VISUAL").

    WitH your method and VB Replace, I can only end up with:

    "Microsoft VISUAL Studio 2010"

    Thanks in advance for any hints :)

    ReplyDelete
  4. Hello again,

    I'm not quite sure what you're asking for. If you search for a value case insensitively, and replace it with the same value in the original case, then you haven't actually replaced anything.

    Do you mean you want to locate the start of a word in a case insensitive manner and then insert some kind of string before and after it to make it bold ?

    ReplyDelete
  5. Yes, that's what I mean - find the occurences (e.g. at which index) of a search text in a string in a case insensitive manner. As mentioned, I want to to insert some text before and after such as HTML tags. Sorry for the unclear question.

    Thanks for any help :)

    ReplyDelete
  6. Hi MD,

    For code that should answer your question, see my latest post here;

    http://www.yortondotnet.com/2010/06/another-string-function.html

    ReplyDelete