Question

Replace Only the First String Match in PHP

phpstring

Question

How can I replace only the first occurrence of $search in $subject in PHP? I need an alternative to str_replace() that leaves all later matches unchanged. Is there a simple, reliable approach?

Short Answer

You will learn why str_replace() replaces every occurrence, how to limit a replacement to the first match, and when to choose a regular-expression or literal-string solution in PHP.

Concept

str_replace() is designed for global replacement: when it finds a matching string, it replaces all occurrences in the subject.

When you need to change only the first match, you need a way to:

  1. Find the position of the first occurrence.
  2. Replace text at that position only.
  3. Keep the rest of the string unchanged.

In PHP, two common approaches are:

  • preg_replace() with a replacement limit of 1.
  • strpos() plus substr_replace() for a literal, non-regex search.

The literal approach is often easiest to reason about because the search text is treated exactly as text. preg_replace() is useful when you already need regular-expression matching.

Mental Model

Imagine a document with the word draft appearing three times.

  • str_replace() is like telling an editor: “Change every draft in this document to final.”
  • A first-only replacement is like saying: “Find the first draft, change it to final, then stop searching.”

strpos() finds the location of that first word, and substr_replace() performs the edit at that exact location.

Take Quiz

Syntax and Examples

For a plain-text search, combine strpos() and substr_replace():

<?php
$subject = "red, blue, red";
$search = "red";
$replacement = "green";

$position = strpos($subject, $search);

if ($position !== false) {
    $result = substr_replace(
        $subject,
        $replacement,
        $position,
        strlen($search)
    );
} else {
    $result = $subject;
}

echo $result; // green, blue, red

strpos() returns the zero-based position of the first match, or false when no match exists. substr_replace() replaces a section of a string:

substr_replace($subject, $replacement, $offset, $length);
  • $offset is where replacement begins.
  • $length is how many characters are removed.
  • strlen($search) removes exactly the matched text.

You can also use preg_replace() with its fourth argument, $limit:

<?php
$subject = "red, blue, red";
$search = "red";
$replacement = "green";

$pattern = '/' . preg_quote($search, '/') . '/';
$result = preg_replace($pattern, $replacement, $subject, 1);

echo $result; // green, blue, red

preg_quote() is important here because it makes special regex characters in $search, such as ., +, and ?, behave as literal characters.

Step by Step Execution

Consider this literal replacement:

<?php
$subject = "cat and cat";
$search = "cat";
$replacement = "dog";

$position = strpos($subject, $search);

if ($position !== false) {
    $result = substr_replace($subject, $replacement, $position, strlen($search));
}

Step by step:

  1. $subject contains "cat and cat".
  2. strpos($subject, "cat") finds the first cat at position 0.
  3. strlen("cat") is 3.
  4. substr_replace() starts at position 0, removes 3 characters, and inserts "dog".
  5. The remaining text, " and cat", stays unchanged.
  6. $result becomes "dog and cat".

If the search text were not found, strpos() would return false, so the if block would not run.

Real World Use Cases

Replacing only the first match is useful when the first occurrence has special meaning:

  • URL cleanup: replace only the first accidental double slash in a path after the protocol has been handled.
  • Template processing: replace the first placeholder, such as {{name}}, while processing values one at a time.
  • Log formatting: redact only the first occurrence of a token in a preview string.
  • User interface text: change the first label or prefix while preserving later mentions.
  • Data migration scripts: update the first matching marker in a legacy text field without changing historical content later in the field.
Take Quiz

Real Codebase Usage

In real PHP projects, developers usually wrap this behavior in a small helper so its intent is clear and the not-found case is handled consistently:

<?php
function replaceFirst(string $subject, string $search, string $replacement): string
{
    if ($search === '') {
        return $subject;
    }

    $position = strpos($subject, $search);

    if ($position === false) {
        return $subject;
    }

    return substr_replace($subject, $replacement, $position, strlen($search));
}

This uses guard clauses:

  • An empty search string returns immediately.
  • A missing match returns the original string.
  • The successful path stays short and readable.

Use preg_replace() instead when the thing you need to find is a pattern, not a fixed string. For example, replacing only the first sequence of digits:

$result = preg_replace('/\d+/', '[number]', $subject, 1);

For user-provided literal search text, do not place it directly into a regex pattern. Escape it with preg_quote().

Common Mistakes

Checking strpos() with if ($position)

This fails when the match starts at position 0, because 0 is treated as false in a boolean condition.

<?php
$position = strpos("cat and dog", "cat");

if ($position) { // Incorrect: $position is 0
    echo "Found";
}

Always compare strictly with false:

if ($position !== false) {
    echo "Found";
}

Using str_replace() and expecting one change

$result = str_replace("cat", "dog", "cat and cat");
// dog and dog

str_replace() has no argument for a replacement limit.

Using unescaped text in preg_replace()

<?php
$search = "file.txt";
$pattern = "/$search/"; // Incorrect for a literal search

In regex, . means “any character,” so this can match text you did not intend. Use:

$pattern = '/' . preg_quote($search, '/') . '/';

Forgetting the empty-search case

An empty search string is usually not meaningful for a replace-first helper. Handle it explicitly to avoid unclear behavior:

if ($search === '') {
    return $subject;
}

Using byte-based functions for text that needs character positions

strpos() and strlen() work with bytes. For user-facing UTF-8 text where character positions matter, consider mb_strpos() and mb_strlen() if the mbstring extension is available.

Comparisons

ApproachBest forFirst match only?Important detail
str_replace()Replacing fixed text everywhereNoReplaces all matches.
strpos() + substr_replace()Replacing the first fixed, literal stringYesCheck with !== false.
preg_replace(..., 1)Replacing the first regex pattern matchYesEscape literal input with preg_quote().
str_ireplace()Case-insensitive replacement everywhereNoLike str_replace(), it replaces all matches.

Choose strpos() plus substr_replace() when searching for an exact piece of text. Choose preg_replace() when matching rules such as “the first number” or “the first run of whitespace.”

Take Quiz

Cheat Sheet

// Replace the first literal occurrence
$position = strpos($subject, $search);

if ($search !== '' && $position !== false) {
    $result = substr_replace($subject, $replacement, $position, strlen($search));
} else {
    $result = $subject;
}
// Replace the first regex match
$result = preg_replace('/pattern/', $replacement, $subject, 1);
// Replace the first literal string using preg_replace
$pattern = '/' . preg_quote($search, '/') . '/';
$result = preg_replace($pattern, $replacement, $subject, 1);

Rules:

  • str_replace() always replaces every occurrence.
  • strpos() returns 0 for a match at the start and false for no match.
  • Use !== false, never just if ($position).
  • substr_replace() needs the matched length: strlen($search).
  • Escape literal search text with preg_quote() before using it in a regex.

FAQ

Can str_replace() replace only the first occurrence in PHP?

No. str_replace() replaces every occurrence of the search string. Use strpos() with substr_replace(), or preg_replace() with a limit of 1.

What is the simplest way to replace the first literal match?

Use strpos() to find the first position, then use substr_replace() at that position.

Why must I use !== false with strpos()?

A valid match may occur at position 0. Since 0 is false-like in PHP, a loose boolean check incorrectly treats that match as missing.

How do I replace only the first regex match in PHP?

Pass 1 as the fourth argument to preg_replace():

preg_replace('/\d+/', 'X', $subject, 1);

Do I need preg_quote() with preg_replace()?

Yes, when your search value should be treated as literal text. It escapes regex metacharacters such as ., *, ?, and +.

What should happen when the search text does not exist?

Usually return the original subject unchanged. This makes the helper predictable and avoids errors.

Is the replacement case-sensitive?

strpos() and the shown preg_replace() examples are case-sensitive. For a case-insensitive literal search, use stripos() to find the position, while still using the correct matched length.

Take Quiz

Mini Project

Description

Create a reusable PHP helper that replaces only the first literal occurrence of a search string. This is useful in text-processing code where a global replacement would change more content than intended.

Goal

Build and test a replaceFirst() function that safely changes one literal match and leaves the rest of the string untouched.

Requirements

  • Create a function named replaceFirst that accepts a subject, search string, and replacement string.
  • Replace only the first occurrence of the search string.
  • Return the original subject when no match exists.
  • Return the original subject when the search string is empty.
  • Demonstrate the function with a string containing at least two matches.
Take Quiz

Keep learning

Related questions

View more