.NET
string manipulation
programming
C#
coding tips

How do I replace the first instance of a string in .NET?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In .NET, string.Replace changes every matching occurrence, which is often too broad. If you only want to replace the first match, the usual approach is to find the first index yourself and rebuild the string around that location.

Replacing the First Literal Match

For ordinary text replacement, IndexOf is the simplest tool. You locate the first occurrence of the old value, then concatenate the unchanged prefix, the new text, and the remaining suffix.

csharp
1using System;
2
3public static class StringUtilities
4{
5    public static string ReplaceFirst(
6        string source,
7        string oldValue,
8        string newValue,
9        StringComparison comparison = StringComparison.Ordinal)
10    {
11        if (source is null)
12            throw new ArgumentNullException(nameof(source));
13
14        if (string.IsNullOrEmpty(oldValue))
15            throw new ArgumentException("oldValue must not be empty.", nameof(oldValue));
16
17        int index = source.IndexOf(oldValue, comparison);
18        if (index < 0)
19            return source;
20
21        return source[..index] + newValue + source[(index + oldValue.Length)..];
22    }
23}

Example usage:

csharp
1string input = "cat scatter catalog";
2string result = StringUtilities.ReplaceFirst(input, "cat", "dog");
3
4Console.WriteLine(result);

The output is dog scatter catalog. Only the first cat changes.

Why IndexOf Works Well Here

This problem is not really about replacement. It is about locating one specific span of text. IndexOf is useful because it already handles the search logic, including optional case rules, and gives you the exact starting position.

Once you have the index, slicing is predictable. The prefix stays untouched, the replacement is inserted once, and the suffix preserves all later matches.

This approach is easy to debug because the control flow is explicit. It is also usually faster and simpler than bringing in regular expressions for a plain substring.

Handling Case Sensitivity Correctly

String matching rules matter. In .NET, StringComparison.Ordinal is usually a good default for identifiers, tokens, and protocol-like values. If the replacement should ignore case, pass StringComparison.OrdinalIgnoreCase.

csharp
1string input = "Hello hello HELLO";
2string result = StringUtilities.ReplaceFirst(
3    input,
4    "hello",
5    "hi",
6    StringComparison.OrdinalIgnoreCase);
7
8Console.WriteLine(result);

This prints hi hello HELLO.

Avoid lowercasing both strings first just to get case-insensitive behavior. That changes the original data and can create subtle bugs in cultures with special casing rules.

Turning It into an Extension Method

If this operation appears in multiple places, an extension method makes the call sites cleaner.

csharp
1using System;
2
3public static class StringExtensions
4{
5    public static string ReplaceFirst(
6        this string source,
7        string oldValue,
8        string newValue,
9        StringComparison comparison = StringComparison.Ordinal)
10    {
11        return StringUtilities.ReplaceFirst(source, oldValue, newValue, comparison);
12    }
13}

Now you can write:

csharp
1string message = "error: timeout. error: retry later";
2string updated = message.ReplaceFirst("error", "warning");
3
4Console.WriteLine(updated);

That reads naturally and keeps the helper reusable.

When Regular Expressions Are Better

If the first thing you want to replace is a pattern instead of a fixed string, use Regex.Replace with a replacement count of 1.

csharp
1using System;
2using System.Text.RegularExpressions;
3
4string input = "Order-100 Order-200 Order-300";
5string result = Regex.Replace(input, @"Order-\d+", "Order-999", 1);
6
7Console.WriteLine(result);

That changes only the first pattern match. This is useful for structured text, but it is more complex than needed for simple literal replacement.

Performance and Allocation Notes

All .NET strings are immutable. Any replacement creates a new string, even if only one small piece changes. That is normal and acceptable for most code.

If you are processing very large text repeatedly in a loop, you may eventually reach for StringBuilder or span-based logic. For one-off first-match replacement, IndexOf plus slicing is usually the right balance of clarity and efficiency.

Common Pitfalls

A common bug is forgetting to check for -1 from IndexOf. If the substring is not found, slicing at that position will fail.

Another issue is allowing an empty oldValue. An empty string technically matches at the start of the source, but that behavior is rarely what callers actually intend.

Developers also sometimes use regex for literal text and then forget that characters such as . or + have special meaning. If you only need a plain substring, stay with IndexOf.

Finally, be explicit about the comparison mode. Case-sensitive and case-insensitive behavior should be a deliberate choice, not an accidental side effect.

Summary

  • 'string.Replace changes every occurrence, not just the first one.'
  • Use IndexOf and slicing for a simple first-match replacement.
  • Pass StringComparison so the caller controls matching rules.
  • Use Regex.Replace only when you need pattern matching.
  • Validate oldValue and handle the no-match case safely.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.