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.
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
titleis the full string"string"is the substring to search forStringComparison.OrdinalIgnoreCasetells 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:
titleis assigned the value"ASTRINGTOTEST".- C# searches inside that string for the substring
"string". - Because
StringComparison.OrdinalIgnoreCaseis used, C# ignores uppercase/lowercase differences. - It checks whether the sequence of letters
s t r i n gappears intitle. "ASTRINGTOTEST"contains"STRING", which matches"string"when case is ignored.- So
foundbecomestrue. Console.WriteLine(found);printsTrue.
Traceable example with a non-match
string title = "ASTRINGTOTEST";
bool found = title.Contains("planet", StringComparison.OrdinalIgnoreCase);
Console.WriteLine(found);
Step by step:
titlecontains the textASTRINGTOTEST.- C# searches for
planet. - Case is ignored, but the letters still must appear in order.
- That substring does not exist.
- 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.
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:
OrdinalIgnoreCasefor technical matchingCurrentCultureIgnoreCasefor 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
| Approach | Example | Case-insensitive | Recommended? | Notes |
|---|---|---|---|---|
Contains("text") | title.Contains("string") | No | Sometimes | Simple, but case-sensitive |
Contains("text", StringComparison.OrdinalIgnoreCase) | title.Contains("string", StringComparison.OrdinalIgnoreCase) | Yes | Yes | Best modern option |
IndexOf(..., StringComparison) >= 0 | title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0 | Yes | Yes | Great fallback for older frameworks |
ToUpper() / ToLower() on both strings | title.ToUpper().Contains(search.ToUpper()) | Usually | Not ideal | Can cause culture issues and extra allocations |
OrdinalIgnoreCase vs CurrentCultureIgnoreCase
| Comparison type | Best for | Notes |
|---|---|---|
OrdinalIgnoreCase | Technical text, identifiers, file-like values, config, commands | Fast and predictable |
CurrentCultureIgnoreCase | User-facing text where language rules matter | Uses the current culture |
InvariantCultureIgnoreCase | Culture-aware but stable across machines | Less common, but useful in some shared formatting scenarios |
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.OrdinalIgnoreCasefor most technical matching. - Avoid
ToUpper()/ToLower()as your default solution. - Use
CurrentCultureIgnoreCaseonly when language-specific user text matters. - If
textmay benull, 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.
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
- Create a list of at least five string titles.
- Ask the user to enter a search term.
- Print only the titles that contain the search term.
- Make the search case-insensitive.
- Handle empty input safely.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.