Toolmingo
Guides6 min read

How to Find and Replace Text (Simple Strings, Regex, and Bulk Edits)

Learn how to find and replace text with plain strings or regular expressions. Covers case-insensitive matching, whole-word replace, backreferences, and code examples in JavaScript, Python, Go, and PHP.

How to Find and Replace Text

Find-and-replace is one of the most fundamental text operations — but it hides surprising complexity once you move beyond simple string substitution. This guide covers plain-string replace, regex replace, case-insensitive matching, whole-word matching, backreferences, and bulk edits across files.


Plain String Replace vs Regex Replace

There are two modes for finding text:

Mode What it matches Example pattern
Plain string Exact characters, no special meaning foo matches only foo
Regex Pattern with wildcards, groups, quantifiers f[oa]o matches foo and fao

For simple word swaps (rename a function, fix a typo), plain string is safer and faster. Regex is necessary when the thing you want to replace varies in form — e.g., all email addresses, all hex colour codes, or all dates in MM/DD/YYYY format.


Case-Insensitive Replace

By default, most engines are case-sensitive: foo does not match Foo or FOO.

Enable case-insensitive matching with:

  • JavaScript regex flag i: /foo/gi
  • Python re.IGNORECASE or re.I
  • Go (?i) inline flag: (?i)foo
  • PHP /foo/i
// Replace "colour" in any capitalisation with "color"
"Colour and colour and COLOUR".replace(/colour/gi, "color");
// "color and color and color"

Whole-Word Replace

Sometimes you want to replace cat but not concatenate or scat. Word-boundary anchors solve this:

  • \bcat\b matches cat as a whole word
  • \b is a zero-width assertion at the boundary between a word character (\w) and a non-word character
"cat concatenate scat category".replace(/\bcat\b/g, "dog");
// "dog concatenate scat category"

Without \b:

"cat concatenate scat".replace(/cat/g, "dog");
// "dog dogcatenate sdog"  ← undesired

Replace All vs Replace First

A common mistake is replacing only the first match:

Language Replace first Replace all
JavaScript str.replace("old", "new") str.replaceAll("old", "new") or /old/g regex
Python str.replace("old", "new", 1) str.replace("old", "new") (replaces all by default)
Go strings.Replace(s, "old", "new", 1) strings.ReplaceAll(s, "old", "new")
PHP str_replace("old", "new", $s) same — replaces all by default

Python and PHP replace all occurrences by default. JavaScript's .replace() with a plain string replaces only the first — a frequent source of bugs.


Using Backreferences to Preserve Parts of the Match

Backreferences let you capture part of the match and reuse it in the replacement. This is the most powerful feature of regex replace.

Example: convert 2026-07-12 to 12/07/2026

"2026-07-12".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1");
// "12/07/2026"
  • (\d{4}) captures the year → $1
  • (\d{2}) captures the month → $2
  • (\d{2}) captures the day → $3

The replacement $3/$2/$1 reorders the captured groups.


Code Examples

JavaScript

const text = "The colour of the sky is colour blue.";

// Plain string — replace all (use replaceAll or /g regex)
const fixed = text.replaceAll("colour", "color");
// "The color of the sky is color blue."

// Case-insensitive regex
const fixedCI = text.replace(/colour/gi, "color");

// Whole-word replace
const wholeWord = "cat scat concatenate".replace(/\bcat\b/g, "dog");
// "dog scat concatenate"

// Backreference: wrap numbers in brackets
const wrapped = "Price is 42 dollars and 7 cents".replace(
  /(\d+)/g,
  "[$1]"
);
// "Price is [42] dollars and [7] cents"

// Named capture groups (ES2018+)
const dated = "2026-07-12".replace(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
  "$<day>/$<month>/$<year>"
);
// "12/07/2026"

Python

import re

text = "The colour of the sky is colour blue."

# Plain string — replaces ALL occurrences by default
fixed = text.replace("colour", "color")
# "The color of the sky is color blue."

# Case-insensitive regex
fixed_ci = re.sub(r"colour", "color", text, flags=re.IGNORECASE)

# Whole-word replace
whole_word = re.sub(r"\bcat\b", "dog", "cat scat concatenate")
# "dog scat concatenate"

# Backreference: reorder date parts
dated = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", "2026-07-12")
# "12/07/2026"

# Replacement using a function (dynamic replacement)
def double_number(m):
    return str(int(m.group()) * 2)

result = re.sub(r"\d+", double_number, "I have 3 cats and 5 dogs")
# "I have 6 cats and 10 dogs"

Go

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    text := "The colour of the sky is colour blue."

    // Plain string — replace all
    fixed := strings.ReplaceAll(text, "colour", "color")
    fmt.Println(fixed) // The color of the sky is color blue.

    // Replace first only
    firstOnly := strings.Replace(text, "colour", "color", 1)
    fmt.Println(firstOnly) // The color of the sky is color blue.

    // Case-insensitive regex
    re := regexp.MustCompile(`(?i)colour`)
    fixedCI := re.ReplaceAllString(text, "color")
    fmt.Println(fixedCI)

    // Whole-word replace
    reWord := regexp.MustCompile(`\bcat\b`)
    result := reWord.ReplaceAllString("cat scat concatenate", "dog")
    fmt.Println(result) // dog scat concatenate

    // Backreference: reorder date
    reDateStr := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`)
    dated := reDateStr.ReplaceAllString("2026-07-12", "$3/$2/$1")
    fmt.Println(dated) // 12/07/2026
}

PHP

<?php
$text = "The colour of the sky is colour blue.";

// Plain string — replaces ALL by default
$fixed = str_replace("colour", "color", $text);
echo $fixed; // The color of the sky is color blue.

// Case-insensitive plain string
$fixedCI = str_ireplace("colour", "color", $text);

// Whole-word replace with regex
$wholeWord = preg_replace('/\bcat\b/', 'dog', 'cat scat concatenate');
echo $wholeWord; // dog scat concatenate

// Backreference: reorder date (use $1 or \\1)
$dated = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', '2026-07-12');
echo $dated; // 12/07/2026

// Replace multiple search terms at once
$result = str_replace(
    ["colour", "behaviour", "neighbour"],
    ["color",  "behavior",  "neighbor"],
    "colour and behaviour of my neighbour"
);
echo $result; // color and behavior of my neighbor
?>

Bulk Find-and-Replace Across Files

For replacing across many files, use command-line tools:

Linux / macOS (sed):

# Replace in-place (-i) across all .txt files recursively
find . -name "*.txt" -exec sed -i 's/colour/color/g' {} +

# With grep to preview first (no replace yet)
grep -r "colour" .

Windows PowerShell:

# Preview matches
Select-String -Path *.txt -Pattern "colour"

# Replace in-place
Get-ChildItem -Recurse -Filter "*.txt" | ForEach-Object {
  (Get-Content $_.FullName) -replace "colour", "color" |
  Set-Content $_.FullName
}

ripgrep + sed (fastest for large codebases):

# Find all files containing the pattern
rg -l "colour"

# Replace using ripgrep's list + sed
rg -l "colour" | xargs sed -i 's/colour/color/g'

Quick Reference

Task JavaScript Python Go PHP
Replace all (plain) .replaceAll(a, b) .replace(a, b) strings.ReplaceAll str_replace
Replace first .replace(a, b) .replace(a, b, 1) strings.Replace(..., 1) preg_replace with limit
Case-insensitive /pattern/gi re.sub(..., flags=re.I) (?i) inline flag /pattern/i
Whole-word /\bword\b/g r"\bword\b" \bword\b /\bword\b/
Backreference $1, $2 (or named $<name>) \1, \2 $1, $2 $1, $2 (or \\1)
Dynamic replace callback in .replace() function in re.sub() ReplaceAllStringFunc preg_replace_callback

Frequently Asked Questions

Why does JavaScript's .replace() only replace the first occurrence?
It's a historical API design: the string overload replaces only the first match. Use .replaceAll() (ES2021+) or a regex with the g flag to replace all occurrences.

What's the difference between str_replace and preg_replace in PHP?
str_replace is a plain-string replacement (fast, no regex overhead). preg_replace accepts a PCRE regular expression, giving you wildcards, quantifiers, and backreferences. Use str_replace for simple swaps; preg_replace when you need pattern matching.

How do I replace a literal dot or parenthesis with regex?
Escape the special character with a backslash: \. matches a literal dot, \( matches a literal opening parenthesis. In JavaScript strings you write "\\." to produce the regex \..

Can I undo a bulk find-and-replace?
Only if you have a backup or version control. Before running sed -i on many files, test with sed without -i first, or commit your changes to git so you can git checkout . if needed.

How do I replace text only within a certain line range?
With sed: sed '5,10s/old/new/g' file.txt applies the substitution only to lines 5 through 10. In Python, read the file into a list of lines, slice the range, apply .replace(), and rejoin.

What are named capture groups and when should I use them?
Named groups ((?<year>\d{4}) in JS/Python, (?P<year>\d{4}) in Python) let you reference captures by name instead of position ($<year> instead of $1). They make complex patterns much more readable and are worth using whenever a pattern has three or more groups.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools