Text Tools

Common Regex Find-and-Replace Mistakes: Greedy Matching and More

Greedy Matching Grabbing Too Much

Quantifiers like * and + are greedy by default — they match as much text as possible, not as little. Trying to match a single HTML tag with <.*> against <b>bold</b> doesn't stop at the first > — it greedily matches all the way to the very last > in the string, capturing far more than intended.

// Fix: use a lazy quantifier
<.*?>

// Or a more specific character class
<[^>]*>

Forgetting to Escape Special Characters

Characters like ., ?, +, (, ), [, and $ have special meaning in regex. If you want to match one of these characters literally — a literal period, for instance — it needs to be escaped with a backslash: \. rather than ., which otherwise matches any character at all.

Only the First Match Gets Replaced

Using .replace() with a plain string (not a regex) only replaces the first occurrence — "a a a".replace("a", "b") produces "b a a", not "b b b". To replace every occurrence, use a regex pattern with the global (g) flag, or use .replaceAll() instead.

A Literal Dollar Sign in the Replacement

Since $1, $2, and similar sequences have special meaning in a replacement string, a genuine literal dollar sign needs to be written as $$ to avoid being misinterpreted as (or accidentally colliding with) a group reference.

Not Accounting for Line Boundaries

By default, ^ and $ match the very start and end of the entire input, not the start and end of each individual line. If you're trying to match something at the beginning or end of every line in a multi-line block of text, you need the multiline flag (m) enabled.

Testing Before Trusting

A pattern that works correctly on one sample input can behave unexpectedly on a different one. Testing your pattern against a few different real examples from your actual text, not just the first case you thought of, catches most of these issues before they cause an unwanted replacement.

Ready to test your own regex pattern?

Open Find and Replace Tool