C# search string
last modified November 6, 2026
In this article we show how to search for strings in C# language.
C# provides several methods for searching strings, including
Contains, StartsWith, EndsWith,
IndexOf, LastIndexOf, and IndexOfAny.
More complex searches can be performed with the Regex class.
Most of these methods have overloads that take a StringComparison
value. It determines whether the comparison is case-sensitive and whether it
uses culture rules. StringComparison.Ordinal compares the
characters' numeric values; it is fast and predictable.
StringComparison.OrdinalIgnoreCase does the same while ignoring
case.
C# Contains
The Contains method returns a boolean value indicating whether the
substring occurs within the specified string.
var text = "An old hawk in the sky";
var word = "hawk";
if (text.Contains(word))
{
Console.WriteLine($"The text contains the {word} word");
}
else
{
Console.WriteLine($"The text does not contain the {word} word");
}
Console.WriteLine(text.Contains("Hawk"));
Console.WriteLine(text.Contains("Hawk", StringComparison.OrdinalIgnoreCase));
Console.WriteLine(text.Contains('k'));
We look for the hawk word in the sentence.
Console.WriteLine(text.Contains("Hawk"));
Console.WriteLine(text.Contains("Hawk", StringComparison.OrdinalIgnoreCase));
By default, Contains performs an ordinal, case-sensitive search.
With StringComparison.OrdinalIgnoreCase, the case of the letters
is ignored.
Console.WriteLine(text.Contains('k'));
There is also an overload that searches for a single character.
$ dotnet run The text contains the hawk word False True True
C# StartsWith and EndsWith
The StartsWith method determines whether the beginning of the
string matches the specified string and the EndsWith method
determines whether the end of the string matches the specified string.
var text = "old hawk";
if (text.StartsWith("old"))
{
Console.WriteLine("The text starts with the old string");
}
else
{
Console.WriteLine("The text does not start with the old string");
}
if (text.EndsWith("hawk"))
{
Console.WriteLine("The text ends with the hawk string");
}
else
{
Console.WriteLine("The text does not end with the hawk string");
}
string[] files = ["report.PDF", "notes.txt", "data.csv", "scan.pdf"];
foreach (var file in files)
{
if (file.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine($"PDF file: {file}");
}
}
We check the beginning and the end of a string. Then we look for PDF files in an array of file names.
if (file.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
File extensions may come in any case. The case-insensitive comparison matches
both report.PDF and scan.pdf.
$ dotnet run The text starts with the old string The text ends with the hawk string PDF file: report.PDF PDF file: scan.pdf
C# IndexOf and LastIndexOf
The IndexOf method finds the zero-based index of the first
occurrence of a specified character or string. The LastIndexOf
method finds the zero-based index of the last occurrence. Both methods return
-1 if the character or string is not found.
var text = "There is an old hawk in the sky. The sun is shining.";
var word = "is";
int first = text.IndexOf(word, StringComparison.Ordinal);
int last = text.LastIndexOf(word, StringComparison.Ordinal);
Console.WriteLine($"The first index of the word {word}: {first}");
Console.WriteLine($"The last index of the word {word}: {last}");
int idx = text.IndexOf("eagle", StringComparison.Ordinal);
Console.WriteLine($"The index of the word eagle: {idx}");
We find the first and last occurrence of the is word.
int first = text.IndexOf(word, StringComparison.Ordinal);
The IndexOf(string) overload without a comparison argument uses
the current culture. Passing StringComparison.Ordinal makes the
search culture-independent; code analyzers recommend stating the comparison
explicitly.
int idx = text.IndexOf("eagle", StringComparison.Ordinal);
The word eagle is not in the text, so the method returns -1.
$ dotnet run The first index of the word is: 6 The last index of the word is: 41 The index of the word eagle: -1
C# find all occurrences
The IndexOf method has an overload with a starting position. We
can use it to find all occurrences of a substring.
var text = "There is an old hawk in the sky. The sun is shining.";
var word = "is";
var indexes = new List<int>();
int pos = text.IndexOf(word, StringComparison.Ordinal);
while (pos != -1)
{
indexes.Add(pos);
pos = text.IndexOf(word, pos + word.Length, StringComparison.Ordinal);
}
Console.WriteLine($"The word {word} occurs {indexes.Count} times");
Console.WriteLine($"Indexes: {string.Join(", ", indexes)}");
We collect the indexes of all occurrences of the is word.
while (pos != -1)
{
indexes.Add(pos);
pos = text.IndexOf(word, pos + word.Length, StringComparison.Ordinal);
}
After each match, we continue the search right after the found substring.
The loop ends when IndexOf returns -1.
$ dotnet run The word is occurs 2 times Indexes: 6, 41
C# IndexOfAny
The IndexOfAny and LastIndexOfAny methods search for
the first and last occurrence of any character from a set.
using System.Buffers;
var text = "An old hawk in the sky";
char[] vowels = ['a', 'e', 'i', 'o', 'u'];
int first = text.IndexOfAny(vowels);
int last = text.LastIndexOfAny(vowels);
Console.WriteLine($"First vowel at {first}: {text[first]}");
Console.WriteLine($"Last vowel at {last}: {text[last]}");
SearchValues<char> digits = SearchValues.Create("0123456789");
var code = "item-AB-2024-x";
int d = code.AsSpan().IndexOfAny(digits);
Console.WriteLine($"First digit at {d}: {code[d]}");
We find the first and the last vowel in the text and the first digit in a product code.
char[] vowels = ['a', 'e', 'i', 'o', 'u']; int first = text.IndexOfAny(vowels); int last = text.LastIndexOfAny(vowels);
The set of characters is passed as an array. The capital A at
the beginning is not in the set, so the first vowel is the o of
old.
SearchValues<char> digits = SearchValues.Create("0123456789");
The SearchValues<char> type, available since .NET 8, holds
a precomputed set of values. When the same set is searched many times, it is
faster than an array.
int d = code.AsSpan().IndexOfAny(digits);
The IndexOfAny overload taking SearchValues is
defined on spans, so we call AsSpan first.
$ dotnet run First vowel at 3: o Last vowel at 17: e First digit at 8: 2
C# Regex Match
The Regex class can be used for more complex searches.
The C# Regex tutorial covers regular expressions
in C# in more detail.
The Success property of a Match indicates whether
the match is successful. The NextMatch method returns a new
Match object with the results for the next match, starting at
the position at which the last match ended. The position of a match is
available in the Index property.
using System.Text.RegularExpressions;
var content = """
Foxes are omnivorous mammals belonging to several genera
of the family Canidae. Foxes have a flattened skull, upright triangular ears,
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every
continent except Antarctica. By far the most common and widespread species of
fox is the red fox.
""";
var rx = new Regex("fox(es)?", RegexOptions.IgnoreCase);
Match match = rx.Match(content);
while (match.Success)
{
Console.WriteLine($"{match.Value} at index {match.Index}");
match = match.NextMatch();
}
Console.WriteLine($"Total matches: {rx.Count(content)}");
We look for all occurrences of the fox word.
var rx = new Regex("fox(es)?", RegexOptions.IgnoreCase);
We add the (es)? expression to include the plural form of the
word. The RegexOptions.IgnoreCase option searches in
case-insensitive mode.
Match match = rx.Match(content);
while (match.Success)
{
Console.WriteLine($"{match.Value} at index {match.Index}");
match = match.NextMatch();
}
The Value property returns the matched string and the
Index property returns its position in the text. The
NextMatch method finds the next occurrence.
Console.WriteLine($"Total matches: {rx.Count(content)}");
The Count method, available since .NET 7, returns the number of
matches without creating Match objects.
$ dotnet run Foxes at index 0 Foxes at index 80 Foxes at index 194 fox at index 292 fox at index 307 Total matches: 5
C# GeneratedRegex
The GeneratedRegex attribute makes the compiler generate the
regular expression code at build time. This avoids the cost of parsing and
compiling the pattern at run time.
using System.Text.RegularExpressions;
var text = "A fox, two foxes, a foxhole, and the Firefox browser.";
foreach (Match m in Patterns.Fox().Matches(text))
{
Console.WriteLine($"{m.Value} at index {m.Index}");
}
static partial class Patterns
{
[GeneratedRegex(@"\bfox(es)?\b", RegexOptions.IgnoreCase)]
public static partial Regex Fox();
}
We search for the whole words fox and foxes.
[GeneratedRegex(@"\bfox(es)?\b", RegexOptions.IgnoreCase)] public static partial Regex Fox();
The attribute is applied to a partial method; the source generator provides
its body. The \b anchors denote word boundaries, so
foxhole and Firefox are not matched.
$ dotnet run fox at index 2 foxes at index 11
Source
String class - language reference
In this article we have searched for strings in C# language.
Author
List all C# tutorials.