3384

Is there a way to make the following return true?

string title = "ASTRINGTOTEST";
title.Contains("string");

There doesn't seem to be an overload that allows me to set the case sensitivity. Currently I UPPERCASE them both, but that's just silly (by which I am referring to the i18n issues that come with up- and down casing).

UPDATE

This question is ancient and since then I have realized I asked for a simple answer for a really vast and difficult topic if you care to investigate it fully.

For most cases, in mono-lingual, English code bases this answer will suffice. I'm suspecting because most people coming here fall in this category this is the most popular answer.

This answer however brings up the inherent problem that we can't compare text case insensitive until we know both texts are the same culture and we know what that culture is. This is maybe a less popular answer, but I think it is more correct and that's why I marked it as such.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Boris Callens
  • 90,659
  • 85
  • 207
  • 305

31 Answers31

3085

You could use the String.IndexOf Method and pass StringComparison.OrdinalIgnoreCase as the type of search to use:

string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Even better is defining a new extension method for string:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source?.IndexOf(toCheck, comp) >= 0;
    }
}

Note, that null propagation ?. is available since C# 6.0 (VS 2015), for older versions use

if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;

USAGE:

string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    Where would be the best place to put something like this within an app structure? – Andrew Nov 18 '10 at 13:59
  • 1
    @Andi, I usually have a couple of code files with general purpose extension methods where this would go. – JaredPar Nov 18 '10 at 17:29
  • @JaredPar: I am curious to know if .Net 4 or .Net 4.5 has this is built in, would you know? – VoodooChild Sep 19 '11 at 15:52
  • 1
    @VoodooChild it doesn't appear so. Judging by the 4.0 API listing here http://msdn.microsoft.com/en-us/library/system.string_methods.aspx – JaredPar Sep 19 '11 at 15:58
  • 1
    Doesn't seem to work within Entity Framework (4.x) queries. Probably because it's within the LINQ to SQL portion. I get the following error:LINQ to SQL does not recognize the method 'Boolean Contains(System.String, System.String, System.StringComparison)' method, and this method cannot be translated into a store expression. A sub-query performed after the results are returned works. I don't think it has anything to do with the extension as much as LINQ to SQL doesn't know how to translate the code to a SQL query. – Roland Schaer Nov 17 '11 at 16:16
  • 1
    there is a reference site for such useful extension, to share the benefit. this is an entry very similar to this one there http://www.extensionmethod.net/Details.aspx?ID=473 – Michael Bahig Feb 16 '12 at 10:56
  • 5
    Great string extension method! I've edited mine to check the source string is not null to prevent any object reference errors from occurring when performing .IndexOf(). – Richard Pursehouse Feb 08 '13 at 10:48
  • 1
    @JookyDFW LINQ to SQL (and LINQ to Entities against a SQL database) will use string comparisons using the default collation in your DB, which in most cases is case-insensitive, so "STRING" and "string" match when hitting the DB, but don't match on the returned results without using this extension. – Timothy Walters Feb 12 '13 at 02:29
  • 13
    This gives the same answer as `paragraph.ToLower(culture).Contains(word.ToLower(culture))` with `CultureInfo.InvariantCulture` and it doesn't solve any localisation issues. Why over complicate things? http://stackoverflow.com/a/15464440/284795 – Colonel Panic Mar 17 '13 at 18:52
  • 86
    @ColonelPanic the `ToLower` version includes 2 allocations which are unnecessary in a comparison / search operation. Why needlessly allocate in a scenario that doesn't require it? – JaredPar Mar 18 '13 at 16:09
  • What about LINQ `IEnumerable.Contains` which let's you specify a `StringComparison` option like `StringComparison.CurrentCultureIgnoreCase`? See MSDN http://msdn.microsoft.com/en-us/library/bb339118(v=vs.95).aspx – seebiscuit Nov 05 '14 at 16:02
  • 6
    @Seabiscuit that won't work because `string` is an `IEnumerable` hence you can't use it to find substrings – JaredPar Nov 06 '14 at 17:55
  • 1
    @fiat This used to be the accepted answer, but is actually not really the correct answer. As long as you stay within the realm of standard Latin characters this looks like a trivial difference, but for large parts of the world it really isn't. The problem is I asked for a simple answer for what I now know is a really difficult topic and the answer really depends on the scenario. I'll update the original question to reflect that. – Boris Callens Aug 26 '15 at 08:23
  • 1
    Just as a style preference, I would just add an explicit method, rather than overload Contains: public static bool ContainsIgnoreCase(this string source, string toCheck) { return source.IndexOf(toCheck, StringComparison.OrdinalIgnoreCase) >= 0; } – What Would Be Cool Sep 21 '15 at 14:45
  • 1
    @CodeBlend most likely they tested all their internal stuff that is aware of their changes, and no one tested (or no one cared) that it broke all external links. – Chris Marisic Jan 28 '16 at 18:17
  • 17
    A word of warning: The default for `string.IndexOf(string)` is to use the current culture, while the default for `string.Contains(string)` is to use the ordinal comparer. As we know, the former can be changed be picking a longer overload, while the latter cannot be changed. A consequence of this inconsistency is the following code sample: `Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string self = "Waldstrasse"; string value = "straße"; Console.WriteLine(self.Contains(value));/* False */ Console.WriteLine(self.IndexOf(value) >= 0);/* True */` – Jeppe Stig Nielsen Feb 18 '16 at 09:40
  • 2
    How could source be null? This is an extension method. – Kyle Delaney Apr 04 '18 at 14:38
  • 4
    @KyleDelaney extension method `this` can be null. I wish C# had a builtin null check there, but it doesn't. – Iain May 22 '18 at 06:05
  • 2
    I did this same extension method, however I null checked instead on the string toCheck, if the coder passes in a null value, the IndexOf method throws a ArgumentNullException anyways. So the extension method could check both source and toCheck to be fault tolerant perhaps. – Tore Aurstad Jun 29 '18 at 17:44
  • 2
    @Iain If you call `myString.SomeMethod()` and `myString` is null you well and truly deserve your null pointer exception. It's not the job of an extension method to check that. – Nyerguds Dec 19 '19 at 12:38
  • @Nyerguds no, calling an extension method on a null pointer _works_. It surprised me when I first saw it, but :shrug: – Iain Apr 14 '20 at 07:01
  • @Iain My point stands; even if that _works_, it's not the job of the method to check that, because extensions are supposed to act like normal functions executed on an object. That said, it is certainly useful to know that little quirk. – Nyerguds Apr 14 '20 at 15:31
  • 2
    @Nyerguds - I often make extension methods specifically for null values. For me, having an extension method work on a null value is a /feature/. As a nice, simple example, I prefer to use an extension method instead of calling `string.IsNullOrEmpty()`. The benefit of this extension method is that I can call it on a null string. Without that benefit, I would have to use the null-conditional operator, followed by a null-coalescing operator (to coalesce the `null` value of the `bool?` to `false`) – Mike Christiansen Sep 17 '21 at 13:58
1576

To test if the string paragraph contains the string word (thanks @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

Where culture is the instance of CultureInfo describing the language that the text is written in.

This solution is transparent about the definition of case-insensitivity, which is language dependent. For example, the English language uses the characters I and i for the upper and lower case versions of the ninth letter, whereas the Turkish language uses these characters for the eleventh and twelfth letters of its 29 letter-long alphabet. The Turkish upper case version of 'i' is the unfamiliar character 'İ'.

Thus the strings tin and TIN are the same word in English, but different words in Turkish. As I understand, one means 'spirit' and the other is an onomatopoeia word. (Turks, please correct me if I'm wrong, or suggest a better example)

To summarise, you can only answer the question 'are these two strings the same but in different cases' if you know what language the text is in. If you don't know, you'll have to take a punt. Given English's hegemony in software, you should probably resort to CultureInfo.InvariantCulture, because it will be wrong in familiar ways.

John Smith
  • 7,243
  • 6
  • 49
  • 61
Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
  • I see your point and you are probably right. This question is ancient and I need to read over it again, but I think I'll change the accepted answer. – Boris Callens Mar 18 '13 at 08:04
  • 78
    Why not `culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0`? That uses the right culture and is case-insensitive, it doesn't allocate temporary lowercase strings, and it avoids the question of whether converting to lowercase and comparing is always the same as a case-insensitive comparison. – Quartermeister Mar 18 '13 at 15:32
  • @Quartermeister that'll work. I tried to find out how `CompareInfo.IndexOf` defines case-insensitive comparison, but the method simply wraps `InternalFindNLSStringEx` which is undocumented. – Colonel Panic Mar 18 '13 at 15:41
  • 11
    This solution also needlessly pollutes the heap by allocating memory for what should be a searching function – JaredPar Mar 18 '13 at 16:09
  • 19
    Comparing with ToLower() will give different results from a case-insensitive IndexOf when two different letters have the same lowercase letter. For example, calling ToLower() on either U+0398 "Greek Capital Letter Theta" or U+03F4 "Greek Capital Letter Theta Symbol" results in U+03B8, "Greek Small Letter Theta", but the capital letters are considered different. Both solutions consider lowercase letters with the same capital letter different, such as U+0073 "Latin Small Letter S" and U+017F "Latin Small Letter Long S", so the IndexOf solution seems more consistent. – Quartermeister Mar 18 '13 at 17:47
  • There is MSDN documentation for FindNLSStringEx, and that probably applies to InternalFindNLSStringEx. The flag is NORM_IGNORECASE, which "ignores any tertiary distinction, whether or not it is actually linguistic case", but I don't know enough about NLS to know what a "tertiary distinction" is. – Quartermeister Mar 18 '13 at 17:53
  • To make this answer a little more complete, considering you want to do web mining: If you don't know the language of a page a-priori, you can quite easily figure out with a simple unigram-based language model. The only problem is getting the data for enough different languages - but probably there are libraries out there that can predict a page's language - i would guess this is a common enough problem. – kutschkem Mar 22 '13 at 19:08
  • @Quartermeister - tertiary distinction is case distinction. Could be linguistic (turkish i -> İ) or not (ascii i -> I). A definition can be found on oracle site: http://docs.oracle.com/cd/B28359_01/server.111/b28298/ch5lingsort.htm#i1006126 more on linguistic casing here: http://blogs.msdn.com/b/michkap/archive/2004/12/11/279942.aspx – Simon Mourier Mar 23 '13 at 08:00
  • 3
    @Quartermeister - and BTW, I believe .NET 2 and .NET4 behave differently on this as .NET 4 always uses NORM_LINGUISTIC_CASING while .NET 2 did not (this flags has appeared with Windows Vista). – Simon Mourier Mar 23 '13 at 08:13
  • 1
    Should you move method with CompareOptions.IgnoreCase to be first, because .ToLower is obviously inefficient? – Michael Freidgeim May 22 '13 at 10:37
  • I would recommend, in the same spirit, adding CompareOptions.IgnoreKanaType and CompareOptions.IgnoreWidth. – Casey Apr 29 '14 at 14:56
  • 12
    Why didn't you write "ddddfg".IndexOf("Df", StringComparison.OrdinalIgnoreCase) ? – Chen Aug 23 '15 at 13:41
  • 1
    I just tried this. I'm searching for 154 string patterns in 40,000 files, ignoring lower case. It is extremely slow and took hours to run. Using Regex or ToLower might be more error prone for non-English searches, but they're both way faster. – James Mar 01 '17 at 16:41
  • 3
    SIK and sik. Big difference. – Bedir Sep 24 '19 at 17:52
  • @Bedir for non-turkish speakers is any elaboration possible? google translate told me they translated to "STYLISH" and "stylish" respectively both showing "Translation verified by Google Translate contributors" – Steve Jun 21 '21 at 08:52
  • 1
    @Steve https://www.seslisozluk.net/en/what-is-the-meaning-of-sik/ – Bedir Jun 21 '21 at 15:02
274

You can use IndexOf() like this:

string title = "STRING";

if (title.IndexOf("string", 0, StringComparison.OrdinalIgnoreCase) != -1)
{
    // The string exists in the original
}

Since 0 (zero) can be an index, you check against -1.

Microsoft .NET Documentation:

The zero-based index position of the value parameter from the start of the current instance if that string is found, or -1 if it is not. If value is Empty, the return value is startIndex.

mkchandler
  • 4,688
  • 3
  • 23
  • 25
198

.NET Core 2.0+ (including .NET 5.0+)

.NET Core has had a pair of methods to deal with this since version 2.0 :

  • String.Contains(Char, StringComparison)
  • String.Contains(String, StringComparison)

Example:

"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);

It is now officially part of the .NET Standard 2.1, and therefore part of all the implementations of the Base Class Library that implement this version of the standard (or a higher one).

Mathieu Renda
  • 14,069
  • 2
  • 35
  • 33
158

Alternative solution using Regex:

bool contains = Regex.IsMatch("StRiNG to search", Regex.Escape("string"), RegexOptions.IgnoreCase);
marsze
  • 15,079
  • 5
  • 45
  • 61
Jed
  • 10,649
  • 19
  • 81
  • 125
  • 7
    Good Idea, also we have a lot of bitwise combinations in RegexOptions like `RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace & RegexOptions.CultureInvariant;` for anyone if helps. – Saravanan Aug 24 '11 at 04:36
  • 8
    Must say I prefer this method although using IsMatch for neatness. – wonea Sep 07 '11 at 17:40
  • 38
    What's worse, since the search string is interpreted as a regex, a number of punctuation chars will cause incorrect results (or trigger an exception due to an invalid expression). Try searching for `"."` in `"This is a sample string that doesn't contain the search string"`. Or try searching for `"(invalid"`, for that matter. – cHao Sep 09 '11 at 13:28
  • 21
    @cHao: In that case, `Regex.Escape` could help. Regex still seems unnecessary when `IndexOf` / extension `Contains` is simple (and arguably more clear). – Dan Mangiarelli Sep 09 '11 at 16:44
  • 9
    Note that I was not implying that this Regex solution was the best way to go. I was simply adding to the list of answers to the original posted question "Is there a way to make the following return true?". – Jed Sep 13 '11 at 15:43
  • @cHao: thanks for highlighting that, illuminating. Still find this prefer this way for the inheritent power of Regexs. – wonea Sep 15 '11 at 10:44
  • 3
    This will be dramatically less efficient than using IndexOf. The use of a Regex will add considerably more processing time, memory, etc. – Liam Sep 15 '15 at 15:47
  • 3
    Because this doesn't work in simple scenarios (".", "no dot here"), this is *not* an "alternate solution". – ANeves Jul 21 '17 at 14:14
  • @Saravanan you confused AND `&` with OR `|`, it shod be `RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant;` instead. – Nekuskus Jul 17 '20 at 11:53
  • Due to the various deficiencies listed, this is not an alternative solution. I invoke Jamie Zawinski's quote on Regex at this point. – David Pierson Feb 14 '22 at 00:15
101

You could always just up or downcase the strings first.

string title = "string":
title.ToUpper().Contains("STRING")  // returns true

Oops, just saw that last bit. A case insensitive compare would *probably* do the same anyway, and if performance is not an issue, I don't see a problem with creating uppercase copies and comparing those. I could have sworn that I once saw a case-insensitive compare once...

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • 4
    Interestingly, I've seen ToUpper() recommended over the use of ToLower() in this sort of scenario, because apparently ToLower() can "lose fidelity" in certain cultures - that is, two different upper-case characters translate to the same lower-case character. – Matt Hamilton Jan 14 '09 at 21:47
  • 143
    Search for "Turkey test" :) – Jon Skeet Jan 14 '09 at 21:48
  • 9
    In some French locales, uppercase letters don't have the diacritics, so ToUpper() may not be any better than ToLower(). I'd say use the proper tools if they're available - case-insensitive compare. – Blair Conrad Jan 14 '09 at 22:03
  • 6
    Don't use ToUpper or ToLower, and do what Jon Skeet said – Peter Gfader Aug 21 '09 at 02:49
  • 18
    Just saw this again after two years and a new downvote... anyway, I agree that there are better ways to compare strings. However, not all programs will be localized (most won't) and many are internal or throwaway apps. Since I can hardly expect credit for advice best left for throwaway apps... I'm moving on :D – Ed S. Jan 25 '11 at 07:28
  • 13
    Is searching for "Turkey test" the same as searching for "TURKEY TEST"? – JackAce Jun 01 '18 at 16:24
  • @JackAce: depends on the application. – Ed S. Jun 06 '18 at 22:12
54

One issue with the answer is that it will throw an exception if a string is null. You can add that as a check so it won't:

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
        return true;

    return source.IndexOf(toCheck, comp) >= 0;
} 
fubo
  • 44,811
  • 17
  • 103
  • 137
FeiBao 飞豹
  • 763
  • 6
  • 6
  • 9
    If toCheck is the empty string it needs to return true per the Contains documentation: "true if the value parameter occurs within this string, or if value is the empty string (""); otherwise, false." – amurra Feb 16 '11 at 16:13
  • 4
    Based on amurra's comment above, doesn't the suggested code need to be corrected? And shouldn't this be added to the accepted answer, so that the best response is first? – David White Aug 30 '11 at 03:43
  • 16
    Now this will return true if source is an empty string or null no matter what toCheck is. That cannot be correct. Also IndexOf already returns true if toCheck is an empty string and source is not null. What is needed here is a check for null. I suggest if (source == null || value == null) return false; – Colin Jul 01 '13 at 12:21
  • 3
    The source cant be null – Lucas Dec 14 '16 at 16:55
  • 3
    `if (string.IsNullOrEmpty(source)) return string.IsNullOrEmpty(toCheck);` – Kyle Delaney Apr 04 '18 at 13:39
  • 1
    So a empty string contains "Foo"... how is that true? – bytedev Oct 19 '18 at 10:21
  • i had to downvote this as well as 6 other people, this is simply wrong. should be `return false;` not `return true;` – Alex Gordon Jun 20 '19 at 18:36
41

StringExtension class is the way forward, I've combined a couple of the posts above to give a complete code example:

public static class StringExtensions
{
    /// <summary>
    /// Allows case insensitive checks
    /// </summary>
    public static bool Contains(this string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Andrew
  • 9,967
  • 10
  • 64
  • 103
  • 1
    why are you allowing ANOTHER layer of abstraction over `StringComparison` ? – Alex Gordon Jun 20 '19 at 18:37
  • 2
    Because this simplifies both reading and writing the code. It's essentially mimicking what later versions of .Net added directly to the class. There's a lot to be said for simple convenience methods that make your life and the life of others easier, even if they do add a little bit of abstraction. – Josh Jan 06 '21 at 11:08
36

This is clean and simple.

Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
Neuron
  • 5,141
  • 5
  • 38
  • 59
takirala
  • 1,891
  • 2
  • 16
  • 36
  • 33
    This will match against a pattern, though. In your example, if `fileNamestr` has any special regex characters (e.g. `*`, `+`, `.`, etc.) then you will be in for quite a surprise. The only way to make this solution work like a proper `Contains` function is to escape `fileNamestr` by doing `Regex.Escape(fileNamestr)`. – XåpplI'-I0llwlg'I - Feb 03 '13 at 15:18
  • 2
    besides, parsing and matching a regex is much more resource-intensive than a simple case-insensitive comparison – phuclv Nov 30 '19 at 05:51
36

OrdinalIgnoreCase, CurrentCultureIgnoreCase or InvariantCultureIgnoreCase?

Since this is missing, here are some recommendations about when to use which one:

Dos

  • Use StringComparison.OrdinalIgnoreCase for comparisons as your safe default for culture-agnostic string matching.
  • Use StringComparison.OrdinalIgnoreCase comparisons for increased speed.
  • Use StringComparison.CurrentCulture-based string operations when displaying the output to the user.
  • Switch current use of string operations based on the invariant culture to use the non-linguistic StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase when the comparison is
    linguistically irrelevant (symbolic, for example).
  • Use ToUpperInvariant rather than ToLowerInvariant when normalizing strings for comparison.

Don'ts

  • Use overloads for string operations that don't explicitly or implicitly specify the string comparison mechanism.
  • Use StringComparison.InvariantCulture -based string
    operations in most cases; one of the few exceptions would be
    persisting linguistically meaningful but culturally-agnostic data.

Based on these rules you should use:

string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
    // The string exists in the original
}

whereas [YourDecision] depends on the recommendations from above.

link of source: http://msdn.microsoft.com/en-us/library/ms973919.aspx

Fabian Bigler
  • 10,403
  • 6
  • 47
  • 70
27

These are the easiest solutions.

  1. By Index of

    string title = "STRING";
    
    if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
    {
        // contains 
    }
    
  2. By Changing case

    string title = "STRING";
    
    bool contains = title.ToLower().Contains("string")
    
  3. By Regex

    Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
    
Lav Vishwakarma
  • 1,380
  • 14
  • 22
19

As simple and works

title.ToLower().Contains("String".ToLower())
Pradeep Asanka
  • 403
  • 1
  • 5
  • 11
14

Just like this:

string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
    Console.WriteLine("yes");
}
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
cdytoby
  • 839
  • 10
  • 26
  • 4
    This is not culture-specific and may fail for some cases. culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) should be used. – hikalkan Jul 22 '14 at 07:50
  • 4
    [Why avoid string.ToLower() when doing case-insensitive string comparisons?](http://stackoverflow.com/questions/28440783/why-avoid-string-tolower-when-doing-case-insensitive-string-comparisons) Tl;Dr *It's costly because a new string is "manufactured".* – Liam Oct 10 '16 at 10:00
13

You can use a string comparison parameter (available from .NET Core 2.1 and above) String.Contains Method.

public bool Contains (string value, StringComparison comparisonType);

Example:

string title = "ASTRINGTOTEST";
title.Contains("string", StringComparison.InvariantCultureIgnoreCase);
Andrew D. Bond
  • 902
  • 1
  • 11
  • 11
dashrader
  • 317
  • 3
  • 14
  • 1
    yes it is available in .net Standard 2.1 and .Net Core 5.0 https://learn.microsoft.com/en-us/dotnet/api/system.string.contains?view=netstandard-2.1 Got fixed as part of - https://github.com/dotnet/runtime/issues/22198 – Surender Singh Malik Jan 19 '21 at 12:40
12

I know that this is not the C#, but in the framework (VB.NET) there is already such a function

Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")

C# variant:

string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");
serhio
  • 28,010
  • 62
  • 221
  • 374
11

The InStr method from the VisualBasic assembly is the best if you have a concern about internationalization (or you could reimplement it). Looking at in it dotNeetPeek shows that not only does it account for caps and lowercase, but also for kana type and full- vs. half-width characters (mostly relevant for Asian languages, although there are full-width versions of the Roman alphabet too). I'm skipping over some details, but check out the private method InternalInStrText:

private static int InternalInStrText(int lStartPos, string sSrc, string sFind)
{
  int num = sSrc == null ? 0 : sSrc.Length;
  if (lStartPos > num || num == 0)
    return -1;
  if (sFind == null || sFind.Length == 0)
    return lStartPos;
  else
    return Utils.GetCultureInfo().CompareInfo.IndexOf(sSrc, sFind, lStartPos, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
}
Casey
  • 3,307
  • 1
  • 26
  • 41
10

Use this:

string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mr.martan
  • 215
  • 3
  • 2
  • 29
    The questioner is looking for `Contains` not `Compare`. – DuckMaestro Jul 11 '11 at 08:05
  • 1
    @DuckMaestro, the accepted answer is implementing `Contains` with `IndexOf`. So this approach is equally helpful! The C# code example on [this page](http://msdn.microsoft.com/en-us/library/ms562040.aspx) is using string.Compare(). SharePoint team's choice that is! – vulcan raven Jan 05 '13 at 10:07
8

Just to build on the answer here, you can create a string extension method to make this a little more user-friendly:

    public static bool ContainsIgnoreCase(this string paragraph, string word)
    {
        return CultureInfo.CurrentCulture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0;
    }
Christian Findlay
  • 6,770
  • 5
  • 51
  • 103
7

Using a RegEx is a straight way to do this:

Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
Stend
  • 137
  • 1
  • 4
  • 6
    Your answer is exactly the same as guptat59's but, as was pointed out on his answer, this will match a regular expression, so if the string you're testing contains any special regex characters it will not yield the desired result. – Casey Dec 09 '13 at 22:55
  • 3
    This is a straight up copy of [this answer](http://stackoverflow.com/a/13302103/542251) and suffers from the same issues as noted in that answer – Liam Oct 10 '16 at 10:04
  • 1
    Agreed. Study regular expressions – Jar Dec 26 '17 at 05:14
7

This is quite similar to other example here, but I've decided to simplify enum to bool, primary because other alternatives are normally not needed. Here is my example:

public static class StringExtensions
{
    public static bool Contains(this string source, string toCheck, bool bCaseInsensitive )
    {
        return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
    }
}

And usage is something like:

if( "main String substring".Contains("SUBSTRING", true) )
....
TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
5

if you want to check if your passed string is in string then there is a simple method for that.

string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";

bool isContained = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;

This boolean value will return if the string is contained or not

shaishav shukla
  • 348
  • 6
  • 11
5

Similar to previous answers (using an extension method) but with two simple null checks (C# 6.0 and above):

public static bool ContainsIgnoreCase(this string source, string substring)
{
    return source?.IndexOf(substring ?? "", StringComparison.OrdinalIgnoreCase) >= 0;
}

If source is null, return false (via null-propagation operator ?.)

If substring is null, treat as an empty string and return true (via null-coalescing operator ??)

The StringComparison can of course be sent as a parameter if needed.

Udi Y
  • 258
  • 3
  • 12
4

The top-rated several answers are all good and correct in their own ways, I write here to add more information, context, and perspective.

For clarity, let us consider that string A contains string B if there is any subsequence of codepoints in A which is equal to B. If we accept this, the problem is reduced to the question of whether two strings are equal.

The question of when strings are equal has been considered in detail for many decades. Much of the present state of knowledge is encapsulated in SQL collations. Unicode normal forms are close to a proper subset of this. But there is more beyond even SQL collations.

For example, in SQL collations, you can be

  • Strictly binary sensitive - so that different Unicode normalisation forms (e.g. precombined or combining accents) compare differently.

    For example, é can be represented as either U+00e9 (precombined) or U+0065 U+0301 (e with combining acute accent).

    Are these the same or different?

  • Unicode normalised - In this case the above examples would be equal to each other, but not to É or e.

  • accent insensitive, (for e.g. Spanish, German, Swedish etc. text). In this case U+0065 = U+0065 U+0301 = U+00e9 = é = e

  • case and accent insensitive, so that (for e.g. Spanish, German, Swedish etc. text). In this case U+00e9 = U+0065 U+0301 = U+00c9 = U+0045 U+0301 = U+0049 = U+0065 = E = e = É = é

  • Kanatype sensitive or insensitive, i.e. you can consider Japanese Hiragana and Katakana as equivalent or different. The two syllabaries contain the same number of characters, organised and pronounced in the (mostly) the same way, but written differently and used for different purposes. For example katakana are used for loan words or foreign names, but hiragana are used for children's books, pronunciation guides (e.g. rubies), and where there is no kanji for a word (or perhaps where the writer does not know the kanji, or thinks the reader may not know it).

  • Full-width or half-width sensitive - Japanese encodings include two representations of some characters for historical reasons - they were displayed at different sizes.

  • Ligatures considered equivalent or not: See https://en.wikipedia.org/wiki/Ligature_(writing)

    Is æ the same as ae or not? They have different Unicode encodings, as do accented characters, but unlike accented characters they also look different.

    Which brings us to...

  • Arabic presentation form equivalence

    Arabic writing has a culture of beautiful calligraphy, where particular sequences of adjacent letters have specific representations. Many of these have been encoded in the Unicode standard. I don't fully understand the rules, but they seem to me to be analogous to ligatures.

  • Other scripts and systems: I have no knowledge whatsoever or Kannada, Malayalam, Sinhala, Thai, Gujarati, Tibetan, or almost all of the tens or hundreds of scripts not mentioned. I assume they have similar issues for the programmer, and given the number of issues mentioned so far and for so few scripts, they probably also have additional issues the programmer ought to consider.

That gets us out of the "encoding" weeds.

Now we must enter the "meaning" weeds.

  • is Beijing equal to 北京? If not, is Bĕijīng equal to 北京? If not, why not? It is the Pinyin romanisation.

  • Is Peking equal to 北京? If not, why not? It is the Wade-Giles romanisation.

  • Is Beijing equal to Peking? If not, why not?

Why are you doing this anyway?

For example, if you want to know if it is possible that two strings (A and B) refer to the same geographical location, or same person, you might want to ask:

  • Could these strings be either Wade-Giles or Pinyin representations of a set of sequences of Chinese characters? If so, is there any overlap between the corresponding sets?

  • Could one of these strings be a Cyrillic transcription of a Chinese Character?

  • could one of these strings be a Cyrillic transliteration of the Pinyin romanisation?

  • Could one of these strings be a Cyrillic transliteration of a Pinyin romanisation of a Sinification of an English name?

Clearly these are difficult questions, which don't have firm answers, and in any case, the answer may be different according to the purpose of the question.

To finish with a concrete example.

  • If you are delivering a letter or parcel, clearly Beijing, Peking, Bĕijīng and 北京 are all equal. For that purpose, they are all equally good. No doubt the Chinese post-offices recognise many other options, such as Pékin in French, Pequim in Portuguese, Bắc Kinh in Vietnamese, and Бээжин in Mongolian.

Words do not have fixed meanings.

Words are tools we use to navigate the world, to accomplish our tasks, and to communicate with other people.

While it looks like it would be helpful if words like equality, Beijing, or meaning had fixed meanings, the sad fact is they do not.

Yet we seem to muddle along somehow.

TL;DR: If you are dealing with questions relating to reality, in all its nebulosity (cloudiness, uncertainty, lack of clear boundaries), there are basically three possible answers to every question:

  • Probably
  • Probably not
  • Maybe
Ben
  • 34,935
  • 6
  • 74
  • 113
3

The trick here is to look for the string, ignoring case, but to keep it exactly the same (with the same case).

 var s="Factory Reset";
 var txt="reset";
 int first = s.IndexOf(txt, StringComparison.InvariantCultureIgnoreCase) + txt.Length;
 var subString = s.Substring(first - txt.Length, txt.Length);

Output is "Reset"

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Mr.B
  • 3,484
  • 2
  • 26
  • 40
3
if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}
Tamilselvan K
  • 1,133
  • 11
  • 10
3

You can use string.indexof () function. This will be case insensitive

FelixSFD
  • 6,052
  • 10
  • 43
  • 117
Okan SARICA
  • 347
  • 4
  • 15
1
public static class StringExtension
{
    #region Public Methods

    public static bool ExContains(this string fullText, string value)
    {
        return ExIndexOf(fullText, value) > -1;
    }

    public static bool ExEquals(this string text, string textToCompare)
    {
        return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExHasAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index]) == false) return false;
        return true;
    }

    public static bool ExHasEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return true;
        return false;
    }

    public static bool ExHasNoEquals(this string text, params string[] textArgs)
    {
        return ExHasEquals(text, textArgs) == false;
    }

    public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
    {
        for (int index = 0; index < textArgs.Length; index++)
            if (ExEquals(text, textArgs[index])) return false;
        return true;
    }

    /// <summary>
    /// Reports the zero-based index of the first occurrence of the specified string
    /// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
    /// A parameter specifies the type of search to use for the specified string.
    /// </summary>
    /// <param name="fullText">
    /// The string to search inside.
    /// </param>
    /// <param name="value">
    /// The string to seek.
    /// </param>
    /// <returns>
    /// The index position of the value parameter if that string is found, or -1 if it
    /// is not. If value is System.String.Empty, the return value is 0.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// fullText or value is null.
    /// </exception>
    public static int ExIndexOf(this string fullText, string value)
    {
        return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
    }

    public static bool ExNotEquals(this string text, string textToCompare)
    {
        return ExEquals(text, textToCompare) == false;
    }

    #endregion Public Methods
}
Final Heaven
  • 124
  • 7
1

Well i came accross this post so i decided to make a benchmark of some of the popular answers and in short JaredPar's answer is the fastest with 0 memory allocation and Colonel Panic's answer is the slowest

Benchmark Info

  • Date: 2023/05
  • .NET SDK: 7.0.103
  • BenchmarkDotNet: 0.13.5
  • CPU: i3-8100
  • OS: Arch Linux

Code Used

[MemoryDiagnoser]
public class StringContains
{
    [Params("How to install Arch Linux?")]
    public string Phrase { get; set; }
    [Params("How to", "arch", "blazor", "random long string to see if it effects the time needed")]
    public string search { get; set; }

    [Benchmark(Baseline = true)]
    public bool Contains() =>
        Phrase.Contains(search, System.StringComparison.CurrentCultureIgnoreCase);

    [Benchmark]
    public bool toUpper() =>
        Phrase.ToUpper().Contains(search.ToUpper());

    [Benchmark]
    public bool toLower() =>
        Phrase.ToLower().Contains(search.ToLower());

    [Benchmark]
    public bool IndexeOf() =>
        Phrase.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;

    [Benchmark]
    public bool CultureCompareInfo()
    {
        var culture = new CultureInfo("en-US");
        return culture.CompareInfo.IndexOf(Phrase, search, CompareOptions.IgnoreCase) >= 0;
    }
}

Results

i deleted some columns because they don't really matter

Method Phrase search Mean Ratio Gen0 Allocated
Contains How t(...)inux? [26] How to 46.887 ns 1.00 - -
toUpper How t(...)inux? [26] How to 88.386 ns 1.89 0.0381 120 B
toLower How t(...)inux? [26] How to 87.196 ns 1.86 0.0381 120 B
IndexeOf How t(...)inux? [26] How to 19.730 ns 0.42 - -
CultureCompareInfo How t(...)inux? [26] How to 166.691 ns 3.56 0.0560 176 B
Contains How t(...)inux? [26] arch 98.794 ns 1.00 - -
toUpper How t(...)inux? [26] arch 86.692 ns 0.88 0.0356 112 B
toLower How t(...)inux? [26] arch 70.534 ns 0.71 0.0254 80 B
IndexeOf How t(...)inux? [26] arch 26.405 ns 0.27 - -
CultureCompareInfo How t(...)inux? [26] arch 219.527 ns 2.22 0.0560 176 B
Contains How t(...)inux? [26] blazor 118.889 ns 1.00 - -
toUpper How t(...)inux? [26] blazor 83.605 ns 0.70 0.0381 120 B
toLower How t(...)inux? [26] blazor 67.559 ns 0.57 0.0254 80 B
IndexeOf How t(...)inux? [26] blazor 13.209 ns 0.11 - -
CultureCompareInfo How t(...)inux? [26] blazor 229.810 ns 1.93 0.0560 176 B
Contains How t(...)inux? [26] rando(...)eeded [55] 95.442 ns 1.00 - -
toUpper How t(...)inux? [26] rando(...)eeded [55] 113.243 ns 1.19 0.0688 216 B
toLower How t(...)inux? [26] rando(...)eeded [55] 86.116 ns 0.90 0.0254 80 B
IndexeOf How t(...)inux? [26] rando(...)eeded [55] 7.380 ns 0.08 - -
CultureCompareInfo How t(...)inux? [26] rando(...)eeded [55] 217.331 ns 2.28 0.0560 176 B

Legends

Phrase : Value of the 'Phrase' parameter

search : Value of the 'search' parameter

Mean : Arithmetic mean of all measurements

Ratio : Mean of the ratio distribution ([Current]/[Baseline])

Gen0 : GC Generation 0 collects per 1000 operations

Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)

1 ns : 1 Nanosecond (0.000000001 sec)

cabiste
  • 97
  • 1
  • 8
1

new version of .net has the feature to ignore the case

examplestring.Contains("exampleSTRING", StringComparison.OrdinalIgnoreCase)
Mohamed Salah
  • 160
  • 1
  • 5
0

Based on the existing answers and on the documentation of Contains method I would recommend the creation of the following extension which also takes care of the corner cases:

public static class VStringExtensions 
{
    public static bool Contains(this string source, string toCheck, StringComparison comp) 
    {
        if (toCheck == null) 
        {
            throw new ArgumentNullException(nameof(toCheck));
        }

        if (source.Equals(string.Empty)) 
        {
            return false;
        }

        if (toCheck.Equals(string.Empty)) 
        {
            return true;
        }

        return source.IndexOf(toCheck, comp) >= 0;
    }
}
-3

Simple way for newbie:

title.ToLower().Contains("string");//of course "string" is lowercase.
O Thạnh Ldt
  • 1,103
  • 10
  • 11