Question

Case-Insensitive String.Contains in C#

csharpstringcontainscase-insensitive

Question

In C#, how can I make string.Contains(...) return true without matching letter casing?

For example:

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

I want this to evaluate to true, even though the casing is different.

There does not appear to be an overload in older code examples that lets me control case sensitivity directly. Right now, one workaround is to convert both strings to uppercase before comparing, but that approach feels wrong because of internationalization and culture-related casing issues.

Short Answer

By the end of this page, you will understand how case-insensitive substring checks work in C#, why simple uppercasing/lowercasing can be risky, and how to use StringComparison or related APIs to perform safer and clearer string searches.

Concept

String comparison is not as simple as checking whether characters look the same. In programming, case-sensitive comparison treats "A" and "a" as different, while case-insensitive comparison treats them as equal.

When you call Contains on a string, you are asking: “Does this larger string include this smaller string?” The important detail is how the comparison is performed.

In C#, string comparisons can be done in different ways:

  • Ordinal: compares raw character values
  • OrdinalIgnoreCase: compares raw character values, ignoring case
  • CurrentCulture: compares using the current culture's language rules
  • CurrentCultureIgnoreCase: same, but ignores case
  • InvariantCulture / InvariantCultureIgnoreCase: culture-aware using invariant rules

This matters because converting both strings with ToUpper() or ToLower() may produce unexpected results in some languages. For example, casing rules differ across cultures, so a manual casing workaround can be less reliable than using the built-in comparison options.

For most programming tasks such as keys, file-like identifiers, protocol values, tags, or technical text matching, StringComparison.OrdinalIgnoreCase is usually the best choice because it is explicit, predictable, and culture-safe for non-linguistic matching.

Mental Model

Think of string searching like checking names on labels.

  • A case-sensitive search is like requiring the label to match exactly, including uppercase and lowercase letters.
  • A case-insensitive search is like saying, “I only care about the letters, not whether they were written in capitals.”

Now imagine doing this in different countries where letter rules can change. If you manually rewrite every label to uppercase first, you may accidentally change the meaning of some letters. Using StringComparison is like telling C#: “Search using these exact matching rules,” instead of rewriting the text yourself first.

Take Quiz

Syntax and Examples

In modern C#, the clearest way is to use the overload of Contains that accepts a StringComparison value:

string title = "ASTRINGTOTEST";
bool result = title.Contains("string", StringComparison.OrdinalIgnoreCase);

Console.WriteLine(result); // True

Why this works

  • title is the full string
  • "string" is the substring to search for
  • StringComparison.OrdinalIgnoreCase tells C# to ignore casing during the comparison

Another common option

If you are working in older frameworks where that overload is not available, use IndexOf:

string title = "ASTRINGTOTEST";
bool result = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;

Console.WriteLine(result); // True

Example with user input

string message = "Welcome To Production";
string search = "production";

if (message.Contains(search, StringComparison.OrdinalIgnoreCase))
{
    Console.WriteLine("Found it.");
}

This is useful when user input may not match the exact capitalization used in your data.

Step by Step Execution

Consider this example:

string title = "ASTRINGTOTEST";
bool found = title.Contains("string", StringComparison.OrdinalIgnoreCase);
Console.WriteLine(found);

Here is what happens step by step:

  1. title is assigned the value "ASTRINGTOTEST".
  2. C# searches inside that string for the substring "string".
  3. Because StringComparison.OrdinalIgnoreCase is used, C# ignores uppercase/lowercase differences.
  4. It checks whether the sequence of letters s t r i n g appears in title.
  5. "ASTRINGTOTEST" contains "STRING", which matches "string" when case is ignored.
  6. So found becomes true.
  7. Console.WriteLine(found); prints True.

Traceable example with a non-match

string title = "ASTRINGTOTEST";
bool found = title.Contains("planet", StringComparison.OrdinalIgnoreCase);
Console.WriteLine(found);

Step by step:

  1. title contains the text ASTRINGTOTEST.
  2. C# searches for planet.
  3. Case is ignored, but the letters still must appear in order.
  4. That substring does not exist.
  5. The result is false.

Real World Use Cases

Case-insensitive substring matching is very common in real programs.

Search boxes

A user searches for report, but your stored title is MonthlyReport2024.

title.Contains("report", StringComparison.OrdinalIgnoreCase)

Filtering logs

You want to detect log entries containing error, warning, or timeout regardless of casing.

logLine.Contains("error", StringComparison.OrdinalIgnoreCase)

API parameter checks

A query string or header may contain values in unpredictable casing.

if (headerValue.Contains("json", StringComparison.OrdinalIgnoreCase))
{
    // Handle JSON response
}

Command parsing

A command-line app may accept commands like START, Start, or start.

if (input.Contains("start", StringComparison.OrdinalIgnoreCase))
{
    // Run command
}

Data cleanup scripts

When scanning imported text from CSV files or external systems, casing often varies, so exact-case matching is too strict.

Take Quiz

Real Codebase Usage

In real codebases, developers usually avoid manual casing conversions and instead choose an explicit comparison strategy.

Common pattern: validation before searching

if (string.IsNullOrEmpty(title))
    return false;

return title.Contains(searchText, StringComparison.OrdinalIgnoreCase);

This uses a guard clause to avoid errors or pointless checks.

Common pattern: fallback for older frameworks

return title?.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;

This is common in legacy code where Contains(..., StringComparison) is unavailable.

Common pattern: filtering collections

var matches = products
    .Where(p => p.Name.Contains("pro", StringComparison.OrdinalIgnoreCase))
    .ToList();

This is typical in search, reporting, or admin tools.

Common pattern: early return

if (string.IsNullOrWhiteSpace(searchText))
    return items;

If there is nothing to search for, return early instead of doing unnecessary work.

Choosing the right comparison rule

In business applications, developers often use:

  • OrdinalIgnoreCase for technical matching
  • CurrentCultureIgnoreCase for user-facing linguistic text

The key is to choose intentionally rather than relying on defaults.

Common Mistakes

1. Converting both strings to uppercase or lowercase

This works sometimes, but it is not the best default approach.

// Less ideal
bool result = title.ToUpper().Contains(search.ToUpper());

Why to avoid it:

  • extra string allocations
  • less clear intent
  • culture-related casing issues

Prefer:

bool result = title.Contains(search, StringComparison.OrdinalIgnoreCase);

2. Forgetting null checks

This will throw if title is null.

string title = null;
bool result = title.Contains("test", StringComparison.OrdinalIgnoreCase); // Error

Safer version:

bool result = title?.Contains("test", StringComparison.OrdinalIgnoreCase) == true;

3. Using the wrong comparison type

Beginners often use culture-aware comparison when they actually want technical matching.

title.Contains("id", StringComparison.CurrentCultureIgnoreCase)

That may be fine for display text, but for identifiers, tags, config values, and protocol-like text, OrdinalIgnoreCase is usually the better choice.

4. Assuming case-insensitive means fuzzy matching

Case-insensitive matching only ignores capitalization. It does not ignore spelling differences.

"Hello".Contains("helo", StringComparison.OrdinalIgnoreCase) // False

5. Forgetting framework version differences

Some older .NET versions do not support Contains(string, StringComparison). In those cases, use IndexOf instead.

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

Comparisons

ApproachExampleCase-insensitiveRecommended?Notes
Contains("text")title.Contains("string")NoSometimesSimple, but case-sensitive
Contains("text", StringComparison.OrdinalIgnoreCase)title.Contains("string", StringComparison.OrdinalIgnoreCase)YesYesBest modern option
IndexOf(..., StringComparison) >= 0title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0YesYesGreat fallback for older frameworks
ToUpper() / ToLower() on both stringstitle.ToUpper().Contains(search.ToUpper())UsuallyNot idealCan cause culture issues and extra allocations

OrdinalIgnoreCase vs CurrentCultureIgnoreCase

Comparison typeBest forNotes
OrdinalIgnoreCaseTechnical text, identifiers, file-like values, config, commandsFast and predictable
CurrentCultureIgnoreCaseUser-facing text where language rules matterUses the current culture
InvariantCultureIgnoreCaseCulture-aware but stable across machinesLess common, but useful in some shared formatting scenarios
Take Quiz

Cheat Sheet

// Best modern option
text.Contains(value, StringComparison.OrdinalIgnoreCase)

// Older framework fallback
text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0

Quick rules

  • Contains("text") is case-sensitive.
  • Use StringComparison.OrdinalIgnoreCase for most technical matching.
  • Avoid ToUpper()/ToLower() as your default solution.
  • Use CurrentCultureIgnoreCase only when language-specific user text matters.
  • If text may be null, use null-safe checks.

Null-safe example

bool found = text?.Contains("abc", StringComparison.OrdinalIgnoreCase) == true;

Older .NET example

bool found = text?.IndexOf("abc", StringComparison.OrdinalIgnoreCase) >= 0;

Remember

  • Case-insensitive != typo-tolerant
  • Ignoring case does not ignore spaces or punctuation
  • The substring must still appear in the same order

FAQ

How do I make Contains case-insensitive in C#?

Use:

text.Contains(value, StringComparison.OrdinalIgnoreCase)

What should I use if my .NET version does not support that overload?

Use IndexOf:

text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0

Why is ToUpper() or ToLower() not the best approach?

Because it can create unnecessary new strings and may behave unexpectedly with culture-specific casing rules.

Should I use OrdinalIgnoreCase or CurrentCultureIgnoreCase?

Use OrdinalIgnoreCase for most technical comparisons. Use CurrentCultureIgnoreCase when matching user-facing natural language text.

Does case-insensitive search ignore spelling differences?

No. It only ignores uppercase/lowercase differences.

Can Contains throw an exception?

Yes. If the source string is null, calling Contains on it will fail. Use a null check or null-conditional operator.

Is IndexOf slower than Contains?

In practice, both are fine for normal use. Choose the clearer API available in your framework version.

Does this work with Unicode text?

Yes, but the behavior depends on the comparison type you choose. That is why using StringComparison explicitly is important.

Take Quiz

Mini Project

Description

Build a simple C# console program that filters a list of article titles using a case-insensitive search term. This demonstrates how substring searching works in realistic code where user input may have different capitalization from stored data.

Goal

Create a program that prints all titles containing a search term, regardless of letter casing.

Requirements

  1. Create a list of at least five string titles.
  2. Ask the user to enter a search term.
  3. Print only the titles that contain the search term.
  4. Make the search case-insensitive.
  5. Handle empty input safely.
Take Quiz

Keep learning

Related questions

View more