Replace & Backrefs
Regex replace transforms strings: str.replace(/pattern/g, replacement). Use captured groups in the replacement, callback functions for complex logic, or named groups for clarity.
Basics, captures, callback, flags
EXAMPLE
// 1) Simple replace — first match only (without /g)
'hello world'.replace(/world/, 'there'); // 'hello there'
'hello world world'.replace(/world/, 'there'); // 'hello there world'
// 2) Global flag — all matches
'hello world world'.replace(/world/g, 'there'); // 'hello there there'
// 3) Case-insensitive
'Hello WORLD'.replace(/world/gi, 'there'); // 'Hello there'
// 4) Use captured groups — $1, $2, ...
'John Smith'.replace(/(\w+) (\w+)/, '$2, $1'); // 'Smith, John'
'2026-06-08'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1'); // '08/06/2026'
// 5) Named groups (ES2018+)
'2026-06-08'.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
'$<day>/$<month>/$<year>',
);
// '08/06/2026'
// 6) Replacement function — most flexible
'hello world'.replace(/\w+/g, (match) => match.toUpperCase());
// 'HELLO WORLD'
'price: 9.99'.replace(/(\d+\.\d+)/, (_, n) => '$' + parseFloat(n).toFixed(2));
// 'price: $9.99'
// Callback gets: match, captured groups ($1, $2, ...), offset, full string
'abc 123 def 456'.replace(/(\w+) (\d+)/g, (match, word, num, offset, full) => {
return `[${word}=${num} at ${offset}]`;
});
// '[abc=123 at 0] [def=456 at 8]'
// 7) With named groups in callback (4th+ arg)
'2026-06-08'.replace(
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,
(_, year, month, day, offset, full, groups) => {
return `${groups.day}/${groups.month}/${groups.year}`;
},
);
// 8) Special replacement patterns
// $& — the whole match
// $$ — literal '$'
// $\` — text BEFORE the match
// $' — text AFTER the match
// $1, $2, ... — capture groups
// $<name> — named capture (modern)
'hello world'.replace(/world/, '[$&]'); // 'hello [world]'
'hello world'.replace(/world/, '$\` matched $&'); // 'hello hello matched world'
// 9) Common recipes
// Trim multiple spaces
'hello world from here'.replace(/\s+/g, ' ').trim();
// 'hello world from here'
// Convert kebab-case to camelCase
'my-variable-name'.replace(/-(\w)/g, (_, c) => c.toUpperCase());
// 'myVariableName'
// Convert camelCase to kebab-case
'myVariableName'.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
// 'my-variable-name'
// Slugify
function slugify(s) {
return s.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
slugify('Hello, World! How are you?'); // 'hello-world-how-are-you'
// Strip HTML tags (NOT safe for security — use DOMPurify)
'<p>hello <b>world</b></p>'.replace(/<[^>]+>/g, '');
// 'hello world'
// Mask credit card (preserve last 4 digits)
'1234567812345678'.replace(/\d(?=\d{4})/g, '*');
// '************5678'
// Add thousands separator
(1234567).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// '1,234,567'
// 10) Multiline replace with flag
const text = `line1
line2
line3`;
text.replace(/^line/gm, '*line');
// '*line1\n*line2\n*line3'
// 11) Replace with conditional logic
const products = 'A 10 B 5 C 20';
products.replace(/(\w) (\d+)/g, (match, name, qty) => {
const q = parseInt(qty);
return q >= 10 ? `${name}=${qty}+` : `${name}=${qty}`;
});
// 'A=10+ B=5 C=20+'
// 12) Replace multiple patterns in one call (array of patterns + replacements)
function multiReplace(text, replacements) {
return replacements.reduce((s, [pattern, replacement]) =>
s.replace(pattern, replacement), text);
}
multiReplace('hello world', [
[/hello/g, 'hi'],
[/world/g, 'there'],
]);
// 'hi there'
// 13) replaceAll (ES2021+) — exact string OR regex
'hello world world'.replaceAll('world', 'there'); // 'hello there there'
'hello WORLD'.replaceAll(/world/gi, 'there'); // 'hello there'
// Note: regex passed to replaceAll MUST have /g flag, else throws TypeError.
// 14) Python — re.sub
import re
re.sub(r'(\w+) (\d+)', r'\2 \1', 'apple 5 banana 10')
# '5 apple 10 banana'
re.sub(r'\\d+', lambda m: str(int(m.group()) * 2), 'a 1 b 2 c 3')
# 'a 2 b 4 c 6'
# Named groups
re.sub(r'(?P<year>\d{4})-(?P<month>\d{2})', r'\g<month>/\g<year>', '2026-06-08')
// 15) PHP — preg_replace
echo preg_replace('/(\w+) (\d+)/', '$2 $1', 'apple 5 banana 10');
// '5 apple 10 banana'
// preg_replace_callback for logic
echo preg_replace_callback(
'/(\d+)/',
fn($m) => $m[1] * 2,
'a 1 b 2 c 3'
);
// 'a 2 b 4 c 6'
// 16) Performance tips
// • For HOT paths, compile / pre-create the regex (avoid re-parsing)
// • String.replace with simple string (no regex) is FAST — use when pattern is literal
// • Greedy quantifiers (.+) can be slow on long inputs — use lazy (.+?) when possible
// • Lookbehind / lookaround supported on modern engines (JS 2018+, PCRE always)
// • Catastrophic backtracking — test patterns against worst-case inputs
// 17) Common bugs
// • Forgetting /g — only first match replaced
// • Special chars in replacement need escape ($ → $$)
// • Using string method instead of regex when you wanted regex semantics
// • Capture group reference in literal mode
// • Newlines in dotall mode (s flag in JS 2018+)
// 18) Best practices
// • Test replacements with edge cases: empty, whitespace, special chars
// • Document complex patterns inline
// • For multi-step transformations, use named functions, not chained replaces
// • Prefer captured-group replacements over fixed strings (more robust to source changes)
// • Use replacement functions for any logic — clearer than $1 dance
Why it matters
Replacement functions unlock the most expressive use of replace — per-match logic, conditional output, group access by name. \$1 / \$& are handy for simple cases; reach for callbacks the moment you need any logic.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
'2026-06-07'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1');
// 07/06/2026
Try it Yourself »
Discussion
Loading…