Implement a Case INsensitive string.Comtains method?

  • Thread starter Thread starter Joe Cool
  • Start date Start date
J

Joe Cool

I would lke to be able to do a case insentive search of a string. I
know this can be done using the VB InStr function, but I refuse to do
it that way. The proper .NET way is to write a custom string class
that exposes an override to the Contains method. Only I am having
problems getting started.

I know I need a class library tp put the code into. But what type of
project do I create? And what class do I need to inherit? Seems that
string is not a choice according to intellisense.

Any help would be appreciated.
 
I would lke to be able to do a case insentive search of a string. I
know this can be done using the VB InStr function, but I refuse to do
it that way. The proper .NET way is to write a custom string class
that exposes an override to the Contains method. Only I am having
problems getting started.

I know I need a class library tp put the code into. But what type of
project do I create? And what class do I need to inherit? Seems that
string is not a choice according to intellisense.

You may or may not need a different project. It might be sufficient to
simply create a new class in your current project, depending on whether
you anticipate reusing this in other projects. If you do create another
project, you'll want to create a C# DLL/class library project (I forget
what the exact terminology in the IDE is, but it something like that).

As far as inheriting goes, you shouldn't need to inherit any class. You
can't inherit System.String, because that class is sealed. If you still
want String-instance semantics, you can write an extension method for
String. For example:

static class MyExtensions
{
public static bool Contains(this string strSearch, string strFind,
StringComparison sc)
{
if (strFind.Length == 0)
{
return true;
}

for (int ich = 0; ich < strSearch.Length - strFind.Length;
ich++)
{
if (strSearch.Substring(ich,
strFind.Length).Equals(strFind, sc))
{
return true;
}
}

return false;
}
}

Then you can use it like this:

string strT = "My dog has fleas";

Console.WriteLine("My string has 'FLEAS': {0}",
strT.Contains("FLEAS", StringComparison.CurrentCultureIgnoreCase));

Any variation on that theme would do also.

Pete
 
Peter Duniho wrote on 24-8-2009 :
You may or may not need a different project. It might be sufficient to
simply create a new class in your current project, depending on whether you
anticipate reusing this in other projects. If you do create another project,
you'll want to create a C# DLL/class library project (I forget what the exact
terminology in the IDE is, but it something like that).

As far as inheriting goes, you shouldn't need to inherit any class. You
can't inherit System.String, because that class is sealed. If you still want
String-instance semantics, you can write an extension method for String. For
example:

static class MyExtensions
{
public static bool Contains(this string strSearch, string strFind,
StringComparison sc)
{
if (strFind.Length == 0)
{
return true;
}

for (int ich = 0; ich < strSearch.Length - strFind.Length;
ich++)
{
if (strSearch.Substring(ich, strFind.Length).Equals(strFind,
sc))
{
return true;
}
}

return false;
}
}

Then you can use it like this:

string strT = "My dog has fleas";

Console.WriteLine("My string has 'FLEAS': {0}",
strT.Contains("FLEAS", StringComparison.CurrentCultureIgnoreCase));

Any variation on that theme would do also.

Pete

Is there a reason why you use a for-loop with a Substring(), instead of
the String.IndexOf(String, StringComparison) method?

Hans Kesting
 
[...]
Any variation on that theme would do also.

Pete

Is there a reason why you use a for-loop with a Substring(), instead of
the String.IndexOf(String, StringComparison) method?

As I wrote: "Any variation on that theme would do also"
 
You may or may not need a different project.  It might be sufficient to 
simply create a new class in your current project, depending on whether  
you anticipate reusing this in other projects.  If you do create another  
project, you'll want to create a C# DLL/class library project (I forget  
what the exact terminology in the IDE is, but it something like that).

As far as inheriting goes, you shouldn't need to inherit any class.  You  
can't inherit System.String, because that class is sealed.  If you still  
want String-instance semantics, you can write an extension method for  
String.  For example:

     static class MyExtensions
     {
         public static bool Contains(this string strSearch, string strFind,  
StringComparison sc)
         {
             if (strFind.Length == 0)
             {
                 return true;
             }

             for (int ich = 0; ich < strSearch.Length - strFind.Length;  
ich++)
             {
                 if (strSearch.Substring(ich,  
strFind.Length).Equals(strFind, sc))
                 {
                     return true;
                 }
             }

             return false;
         }
     }

Then you can use it like this:

     string strT = "My dog has fleas";

     Console.WriteLine("My string has 'FLEAS': {0}",
         strT.Contains("FLEAS", StringComparison.CurrentCultureIgnoreCase));

Any variation on that theme would do also.

Thanks. Most informative part of this reply was your reference to
"extension methods". I was not aware of them. Cool. Gonna make sure I
remember that little trick.

Next thing was making me aware of another item I was unaware of, the
StringComparison enumeration.

Th documentation on the StringComparsion enumeration mentions it is
used by the String.Compare and String.Equals methods. It didn't
mention the String.IndexOf method as another responder mentions but
sure enough, the documentation shows that method does have overload(s)
that does.

This is a rhetorical question, but it seems strange that at least
three String class methods supports an overload that makes use of the
StringComparison enumeration, I wonder how come there isn't an
overload of the Contains method that also does???

Well, as you have shown, at least we can write our own.
 
You may or may not need a different project.  It might be sufficient to 
simply create a new class in your current project, depending on whether  
you anticipate reusing this in other projects.  If you do create another  
project, you'll want to create a C# DLL/class library project (I forget  
what the exact terminology in the IDE is, but it something like that).

As far as inheriting goes, you shouldn't need to inherit any class.  You  
can't inherit System.String, because that class is sealed.  If you still  
want String-instance semantics, you can write an extension method for  
String.  For example:

     static class MyExtensions
     {
         public static bool Contains(this string strSearch, string strFind,  
StringComparison sc)
         {
             if (strFind.Length == 0)
             {
                 return true;
             }

             for (int ich = 0; ich < strSearch.Length - strFind.Length;  
ich++)
             {
                 if (strSearch.Substring(ich,  
strFind.Length).Equals(strFind, sc))
                 {
                     return true;
                 }
             }

             return false;
         }
     }

Then you can use it like this:

     string strT = "My dog has fleas";

     Console.WriteLine("My string has 'FLEAS': {0}",
         strT.Contains("FLEAS", StringComparison.CurrentCultureIgnoreCase));

Any variation on that theme would do also.

I tried to implement this but I get a build error, says it can't find
the type System.Runtime.CompilerServices.ExtensionAttribute. Says I am
missing a reference to System.Core.dll. But when I try to add a
reference, System.Core is grayed out.

???
 
Joe Cool has brought this to us :
I tried to implement this but I get a build error, says it can't find
the type System.Runtime.CompilerServices.ExtensionAttribute. Says I am
missing a reference to System.Core.dll. But when I try to add a
reference, System.Core is grayed out.

???

You are not using the 3.5 framework, which you need for the extension
methods to work (although there are tricks to work around that).
So switch your project to the 3.5 framework (see the properties) and it
will work.

Hans Kesting
 
Hans Kesting said:
Joe Cool has brought this to us :

You are not using the 3.5 framework, which you need for the extension
methods to work (although there are tricks to work around that).
So switch your project to the 3.5 framework (see the properties) and it
will work.

Hans Kesting

Here is the work around:

//override the .net 3.5 compiler services for .net 2.0 compatibility
//see: http://kohari.org/2008/04/04/extension-methods-in-net-20/
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false,
Inherited = false)]
public class ExtensionAttribute : Attribute
{

}
}

Now you can use extensions with framwork 2.0

/FStampe
 
Hello Joe,
I would lke to be able to do a case insentive search of a string. I
know this can be done using the VB InStr function, but I refuse to do
it that way. The proper .NET way is to write a custom string class
that exposes an override to the Contains method. Only I am having
problems getting started.

I know I need a class library tp put the code into. But what type of
project do I create? And what class do I need to inherit? Seems that
string is not a choice according to intellisense.

Any help would be appreciated.

Why not keep it (overly) simple?

public bool fnStringContains(string strFirstString, string strSecondString)
{
bool blResults = false;
blResults = strFirstString.ToLower().Contains(strSecondString.ToLower());
return blResults;
}

Karl
 
Joe Cool has brought this to us :








You are not using the 3.5 framework, which you need for the extension
methods to work (although there are tricks to work around that).
So switch your project to the 3.5 framework (see the properties) and it
will work.


Would have been nice if the help text, namely "How to: Implement and
Call a Custom Extension Method (C# Programming Guide)" had mentioned
that the topic applied only to .NER Frameword 3.5.

Anyhoo, that was it. I was working with a project I had converted from
VS2005 anf forgot to upgrade the framework version.
 
Would have been nice if the help text, namely "How to: Implement and
Call a Custom Extension Method (C# Programming Guide)" had mentioned
that the topic applied only to .NER Frameword 3.5.

Anyhoo, that was it. I was working with a project I had converted from
VS2005 anf forgot to upgrade the framework version.

=====================

check out my last posting from around 8 hours before yours... There i have
given you the way to implement it into framework 2.0. Just did it myself and
it works like a charm..

/FStampe
 
Would have been nice if the help text, namely "How to: Implement and
Call a Custom Extension Method (C# Programming Guide)" had mentioned
that the topic applied only to .NER Frameword 3.5.

It does, sort of. You need to look at what section of MSDN you're
reading. A topic may or may not include the "There are other versions of
this in..." box on the web site, but if it doesn't, the first thing to
realize is that that means it's only in the most recent .NET, and the
second thing to realize is that you can look at the navigation tree or the
"bread crumbs" along the top to see what version of the docs you're
looking at.

Pete
 
[...]
This is a rhetorical question, but it seems strange that at least
three String class methods supports an overload that makes use of the
StringComparison enumeration, I wonder how come there isn't an
overload of the Contains method that also does???

Yes, it seems like an odd omission. But, sometimes that sort of thing
happens. :)
 
Why not keep it (overly) simple?

public bool fnStringContains(string strFirstString, string
strSecondString)
{
bool blResults = false;
blResults =
strFirstString.ToLower().Contains(strSecondString.ToLower());
return blResults;
}

Because that won't produce correct results in all locales. It's probably
fine for English, and some other languages. But there are other languages
where it's not (the classic example being Turkish).

Pete
 
Peter said:
Because that won't produce correct results in all locales. It's
probably fine for English, and some other languages. But there are
other languages where it's not (the classic example being Turkish).

Pete

I personally would go with Karl solution.
ToLower() will use CurrentCulture as default. If the OP ever need to use
diffent culture, ToLower method have an overload for that. Wrap that
into extension method...

internal class MyExtension
{
public string bool Contains(this string source, string value)
{
return source.ToLower().Contains(value.ToLower());
}

public string bool Contains(this string source, string value,
CultureInfo culture)
{
return source.ToLower(culture).Contains(value.ToLower(culture));
}
}

Regards.
 
kndg said:
I personally would go with Karl solution.
ToLower() will use CurrentCulture as default. If the OP ever need to use
diffent culture, ToLower method have an overload for that. Wrap that
into extension method...

internal class MyExtension
{
public string bool Contains(this string source, string value)
{
return source.ToLower().Contains(value.ToLower());
}

public string bool Contains(this string source, string value,
CultureInfo culture)
{
return source.ToLower(culture).Contains(value.ToLower(culture));
}
}

Regards.

Arghh... damn!
The first method does not works as it has the same signature with
String.Contains(string value) method. Either change the name to
ContainsEx or something like that, or just use the second method and
pass the CultureInfo.CurrentCulture as the parameter.

Regards.
 
I personally would go with Karl solution.

And you would run into the same bug that Karl would, should he ever
actually use it.
ToLower() will use CurrentCulture as default. If the OP ever need to use
diffent culture, ToLower method have an overload for that. Wrap that
into extension method...

It's not a question of choosing the culture. It's the fact that no matter
what the culture, simply changing the case of the string and comparing
will not necessarily produce the same results as doing an actual "case
insensitive" comparison for that culture.

Pete
 
Peter said:
[...]
It's not a question of choosing the culture. It's the fact that no
matter what the culture, simply changing the case of the string and
comparing will not necessarily produce the same results as doing an
actual "case insensitive" comparison for that culture.

Pete

Hi Pete,

I'm not literally sure what do you mean by the above statement.
Would you give one test case / example that my method will fail (and
yours succeed)?
 
Peter said:
[...]
It's not a question of choosing the culture. It's the fact that no
matter what the culture, simply changing the case of the string and
comparing will not necessarily produce the same results as doing an
actual "case insensitive" comparison for that culture.
Pete

Hi Pete,

I'm not literally sure what do you mean by the above statement.
Would you give one test case / example that my method will fail (and
yours succeed)?

It will depend on why one is doing the comparison as to whether the
difference would be considered a "failure". But, if you're interested in
further reading, here are a couple of pages that should get you headed in
the right direction:
http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html
http://www.i18nguy.com/unicode/turkish-i18n.html

Previous threads in this newsgroup discussing the topic:
http://groups.google.com/group/micr...csharp/browse_thread/thread/a2d404b1d7da17be/
http://groups.google.com/group/micr...aspnet/browse_thread/thread/23b40b19185821d9/

Pete
 
Hello Peter,
Because that won't produce correct results in all locales. It's
probably fine for English, and some other languages. But there are
other languages where it's not (the classic example being Turkish).

Pete
I did mention that it's overly simple :)

Thanks, Pete - I did not know that.

Of course, I work for a government agency in the US, and we don't do too
many Turkish language comparisons, so it works here.

I will read the links you provided for kndg though.

I'm keen to learn, after all.

Kar
 
Back
Top