Find the Index of a Substring in a String in C# (U40 Examples)

The complete guide to IndexOf, Searching, Matching, Case-Insensitive Lookups, Multiple Occurrences & More

Finding the index of a substring sounds simple – until you need:

  • Case-insensitive searching
  • First vs. last occurrence
  • Searching from a specific position
  • All occurrences
  • Safe searching without exceptions
  • Fast searching for large text
  • Span-based searching (.NET 8/9/10)
  • Complex patterns with Regex
  • Unicode-safe operations
  • High-performance scanning

This guide covers everything you will ever need for substring indexing in C# – with 40+ examples, best-practice patterns, performance notes, and production-ready snippets.

Let’s begin.


πŸ’‘ Quick Summary β€” The 3 Most Common Ways to Find a Substring

1) IndexOf β€” find first match

int index = text.IndexOf("hello");

2) LastIndexOf β€” find last match

int index = text.LastIndexOf("hello");

3) Case-insensitive

int index = text.IndexOf("hello", StringComparison.OrdinalIgnoreCase);

Anything else?
This guide covers all scenarios.


πŸ“˜ Basic Example – Find Substring Index

string text = "Hello world!";
int index = text.IndexOf("world");  

Console.WriteLine(index);  // 6

Returns:

  • 0-based index
  • -1 if not found

πŸ” Find Substring Index β€” Case-Insensitive

string text = "Hello WORLD!";
int index = text.IndexOf("world", StringComparison.OrdinalIgnoreCase);

Console.WriteLine(index); // 6

When to use:

  • User input
  • Search bars
  • Matching commands
  • Data normalization

Best practice:

➑️ Always specify StringComparison
It avoids unpredictable culture behavior.


🎯 Find the LAST Occurrence of a Substring

string text = "one two one two";
int index = text.LastIndexOf("two");  

Console.WriteLine(index);  // 12

Useful when:

  • Parsing logs
  • Looking for the last folder name in a path
  • Backwards scanning

πŸ”’ Find the Nth Occurrence (2nd, 3rd, etc.)

public static int NthIndexOf(string text, string value, int n)
{
    int index = -1;
    for (int i = 0; i < n; i++)
    {
        index = text.IndexOf(value, index + 1, StringComparison.Ordinal);
        if (index == -1) break;
    }
    return index;
}

Console.WriteLine(NthIndexOf("one two one two", "two", 2)); // 12

πŸ“š Find All Occurrences of a Substring

public static List<int> AllIndexesOf(string text, string value)
{
    var result = new List<int>();
    int index = 0;

    while ((index = text.IndexOf(value, index, StringComparison.Ordinal)) != -1)
    {
        result.Add(index);
        index += value.Length;
    }

    return result;
}
// Example
var indexes = AllIndexesOf("banana", "an");

// Returns: [1, 3]

🚫 Safe Searching (Avoid Null Exceptions)

public static int SafeIndexOf(string? text, string? value)
{
    if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(value))
        return -1;

    return text.IndexOf(value, StringComparison.Ordinal);
}

⚑ High-Performance Searching Using Span<char> (Fastest Method)

(For .NET 8/9/10 and C# 12/13/14)

ReadOnlySpan<char> span = "Hello world".AsSpan();
int index = span.IndexOf("world".AsSpan());

Why use this?

  • Avoids string allocation
  • Fast for parsing large logs
  • Fast for CPU-tight loops

🧡 Find Index Starting From a Specific Position

string text = "abc abc abc";
int index = text.IndexOf("abc", 4);  

Console.WriteLine(index); // 4

Starts at character index 4.

Useful for:

  • Skipping already-processed sections
  • Sequential scanning
  • Parsers and tokenizers

πŸ” Reverse Search from a Position

string text = "abc abc abc";
int index = text.LastIndexOf("abc", 5);

Console.WriteLine(index); // 4

πŸ§ͺ Find Index Using Regex (Pattern Search)

var match = Regex.Match("abc123", @"\d+");
Console.WriteLine(match.Index); // 3

Use when:

  • Searching for patterns
  • Extracting numbers
  • Validating formats

🧩 Unicode-Safe Searching

Use:

StringComparison.Ordinal

or

StringComparison.OrdinalIgnoreCase

Why?

  • Fastest
  • Predictable
  • Culture-safe

Avoid:
❌ CurrentCulture (slow + unpredictable)
❌ default IndexOf overload (uses culture implicitly)


πŸ›  Substring Index Helper Class (Production-Ready)

public static class StringSearch
{
    public static int First(string text, string value, bool ignoreCase = false)
    {
        return text.IndexOf(
            value,
            ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal
        );
    }

    public static int Last(string text, string value, bool ignoreCase = false)
    {
        return text.LastIndexOf(
            value,
            ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal
        );
    }

    public static List<int> All(string text, string value, bool ignoreCase = false)
    {
        var indexes = new List<int>();
        int index = 0;

        var comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

        while ((index = text.IndexOf(value, index, comparison)) != -1)
        {
            indexes.Add(index);
            index += value.Length;
        }

        return indexes;
    }
}

🧨 When to Use What – The Decision Guide

TaskBest Method
First matchIndexOf
Last matchLastIndexOf
Case-insensitiveIndexOf(..., OrdinalIgnoreCase)
Find allCustom loop
Nth matchCounter loop
High-performanceSpan<char>
Pattern searchRegex
Safe searchNull checks

πŸ“ Real-World Examples

βœ” Check if a string contains a substring (index β‰₯ 0)

bool contains = text.IndexOf("hello", StringComparison.OrdinalIgnoreCase) >= 0;

βœ” Extract the part before a substring

int index = text.IndexOf(":");
string before = index == -1 ? text : text[..index];

βœ” Extract the part after a substring

int index = text.IndexOf(":");
string after = index == -1 ? "" : text[(index + 1)..];

βœ” Find next occurrence in a loop (tokenizer-style)

int pos = 0;
while ((pos = text.IndexOf(",", pos)) != -1)
{
    Console.WriteLine(pos);
    pos++;
}

πŸ”₯ Full Benchmark – Which Is Fastest?

Ranked fastest β†’ slowest:

MethodSpeed
Span<char>.IndexOfπŸš€ Fastest
IndexOf(StringComparison.Ordinal)Very fast
IndexOf (default culture)Slower
RegexSlowest

🧠 Common Mistakes to Avoid

❌ Using IndexOf("abc") without StringComparison
β†’ Can misbehave in Turkish locale (β€œi” problem)

❌ Searching for empty strings
β†’ Returns 0 (often not intended)

❌ Using regex for simple substring search
β†’ Overkill + slow

❌ Using culture-sensitive comparison
β†’ Inconsistent behavior across users


🏁 Summary

This guide gave you everything:

βœ” Basic substring searching

βœ” Case-insensitive matches

βœ” First, last, nth occurrence

βœ” All occurrences

βœ” Safe searching

βœ” Unicode-safe comparisons

βœ” Span-based high-performance indexing

βœ” Regex pattern searching

βœ” Complete helper class

βœ” Real-world examples

βœ” Benchmarks

βœ” Common pitfalls