Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Implement a Case INsensitive string.Comtains method?

161 views
Skip to first unread message

Joe Cool

unread,
Aug 23, 2009, 10:27:47 PM8/23/09
to
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.

Peter Duniho

unread,
Aug 23, 2009, 11:50:12 PM8/23/09
to

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

Hans Kesting

unread,
Aug 24, 2009, 4:02:15 AM8/24/09
to

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

Hans Kesting


Peter Duniho

unread,
Aug 24, 2009, 1:05:30 PM8/24/09
to
On Mon, 24 Aug 2009 01:02:15 -0700, Hans Kesting
<news....@spamgourmet.com> wrote:

> [...]


>> 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"

Joe Cool

unread,
Aug 24, 2009, 10:35:55 PM8/24/09
to
On Aug 23, 11:50 pm, "Peter Duniho" <no.peted.s...@no.nwlink.spam.com>
wrote:

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.

Joe Cool

unread,
Aug 24, 2009, 11:55:57 PM8/24/09
to
On Aug 23, 11:50 pm, "Peter Duniho" <no.peted.s...@no.nwlink.spam.com>
wrote:

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.

???

Hans Kesting

unread,
Aug 25, 2009, 6:22:46 AM8/25/09
to
Joe Cool has brought this to us :
> On Aug 23, 11:50ï¿œpm, "Peter Duniho" <no.peted.s...@no.nwlink.spam.com>

> wrote:
>> On Sun, 23 Aug 2009 19:27:47 -0700, Joe Cool <joecool1...@live.com> wrote:
>>> 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.
>
> 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


Finn Stampe Mikkelsen

unread,
Aug 25, 2009, 8:09:08 AM8/25/09
to
"Hans Kesting" <news....@spamgourmet.com> skrev i meddelelsen
news:%23$%23U%233WJK...@TK2MSFTNGP04.phx.gbl...

> Joe Cool has brought this to us :

>>> 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.
>>
>> ???
>
> 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

Karl Mitschke

unread,
Aug 25, 2009, 4:07:13 PM8/25/09
to
Hello Joe,

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

unread,
Aug 25, 2009, 4:30:19 PM8/25/09
to
On Aug 25, 6:22 am, Hans Kesting <news.han...@spamgourmet.com> wrote:
> Joe Cool has brought this to us :
>
>
>
>
>
> > On Aug 23, 11:50 pm, "Peter Duniho" <no.peted.s...@no.nwlink.spam.com>

> > wrote:
> >> On Sun, 23 Aug 2009 19:27:47 -0700, Joe Cool <joecool1...@live.com> wrote:
> >>> 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.
>
> > 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.
>


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.

Finn Stampe Mikkelsen

unread,
Aug 25, 2009, 7:20:35 PM8/25/09
to

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

Peter Duniho

unread,
Aug 25, 2009, 8:17:44 PM8/25/09
to
On Mon, 24 Aug 2009 19:35:55 -0700, Joe Cool <joeco...@live.com> wrote:

> [...]


> 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. :)

Peter Duniho

unread,
Aug 25, 2009, 8:17:07 PM8/25/09
to
On Tue, 25 Aug 2009 13:30:19 -0700, Joe Cool <joeco...@live.com> wrote:

> 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

Peter Duniho

unread,
Aug 25, 2009, 8:19:08 PM8/25/09
to
On Tue, 25 Aug 2009 13:07:13 -0700, Karl Mitschke
<karlmi...@somestate.gov> wrote:

> 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

kndg

unread,
Aug 26, 2009, 12:07:26 AM8/26/09
to

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

unread,
Aug 26, 2009, 12:20:25 AM8/26/09
to

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.

Peter Duniho

unread,
Aug 26, 2009, 1:37:09 AM8/26/09
to
On Tue, 25 Aug 2009 21:07:26 -0700, kndg <re...@this.newsgroup> wrote:

> 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

kndg

unread,
Aug 26, 2009, 2:24:13 AM8/26/09
to
Peter Duniho wrote:
> [...]

> 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 Duniho

unread,
Aug 26, 2009, 3:37:38 AM8/26/09
to

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/microsoft.public.dotnet.languages.csharp/browse_thread/thread/a2d404b1d7da17be/
http://groups.google.com/group/microsoft.public.dotnet.framework.aspnet/browse_thread/thread/23b40b19185821d9/

Pete

Karl Mitschke

unread,
Aug 26, 2009, 10:30:12 AM8/26/09
to
Hello Peter,

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.

Karl


kndg

unread,
Aug 26, 2009, 10:43:34 AM8/26/09
to
Hi Pete,

Thanks for the great links.
Yes, you are correct. My method fails if pass with Turkish characters.
For example:
"Hİ all".Contains("HI", CultureInfo.CurrentCulture) returns true where
it should return false.

After reading through your link and MSDN documentation about character
casing, now it becomes clear to me. For those who are interested to
know, this is what actually happens:
(I found that Unicode documentation also helps.
http://www.unicode.org/versions/Unicode5.0.0/ch05.pdf#G21180)

"Hİ all".ToLower() is converted to "hi all". (Actually if follow unicode
documentation it becomes h+i+[U0307]+ +a+l+l)
"HI".ToLower() will become "hi".

Since "hi" is contained in "hi all", so the output returns true (which
is incorrect).

Pete's method use String.Equal with StringComparison option for
comparison. Under the hood, it use native API which takes care of the
above headache.

Lesson learned: Do not use ToLower() or ToUpper() for string comparison.

Regards.

0 new messages