Find and Replace with Regular Expressions: A Practical Guide
July 27, 2026 · DevTools
You need to rename 300 API endpoints from /v1/getUser to /v2/getUser. A manual edit would take all day and introduce typos. A plain-text find-and-replace catches all 300 at once — but /v1/ appears in many places you do not want to change (comments, docs, test fixtures). What you actually need is to replace /v1/ only when it is followed by a known set of route names.
That is where regex find-and-replace earns its place. The same tool that lets you search precisely lets you replace precisely — with capture groups, backreferences, and conditional patterns that no plain-text search can match.
The Find and Replace Text tool supports both literal and regex modes. Here is what regex mode unlocks.
Literal vs. regex mode: the critical difference
In literal mode, the search string is taken literally: $ searches for the dollar sign character. In regex mode, $ is an anchor matching the end of a line. If you type price: $50 in regex mode expecting to match the literal string, you will get unexpected results — or an error.
The Find and Replace Text defaults to literal mode. Always confirm which mode you are in before running a replace, especially when your search string contains characters that are regex metacharacters: ., *, +, ?, [, ], (, ), {, }, ^, $, |, \.
Capture groups and backreferences
Parentheses in a regex define a capture group. In the replacement string, $1, $2, $3 refer to the captured text. This is the most useful feature for batch renaming.
Rename endpoints:
Search: /v1/(getUser|createUser|deleteUser)
Replace: /v2/$1
/v1/getUser becomes /v2/getUser. createUser and deleteUser are renamed too. Without capture groups, you would need three separate searches.
Swap two words:
Search: (\w+), (\w+)
Replace: $2 $1
Smith, John becomes John Smith. The comma and space are matched but not captured — they are preserved in the output.
The dot, greediness, and lazy matching
. matches any character except newline. .* matches any sequence of characters. By default, .* is greedy — it matches as much as possible. Given the string <b>bold</b> and <b>more</b>:
Search: <b>.*</b>
Replace: [BOLD]
Greedy .* matches from the first <b> all the way to the last </b> — producing [BOLD] instead of two separate matches. The fix is lazy matching: .*? matches as few characters as possible.
Search: <b>.*?</b>
Replace: [BOLD]
Now it matches <b>bold</b> and <b>more</b> separately.
Anchors: start and end of line
^ matches the start of a line. $ matches the end.
# Add a prefix to every line that starts with "ERROR"
Search: ^(ERROR.*)
Replace: [ALERT] $1
# Trim trailing whitespace from every line
Search: \s+$
Replace: (empty)
Alternation for multiple patterns
| means "or". Use it to catch multiple variants:
Search: (deprecated|obsolete|will-be-removed-in-v\d+)
Replace: [LEGACY: $1]
This catches three different deprecation styles and tags them uniformly.
Negative lookahead and lookbehind
These let you match a pattern only when it is not followed by (or preceded by) something. They do not consume characters — they assert a condition.
Replace foo only when not followed by Bar:
Search: foo(?!Bar)
Replace: replacement
Replace foo only when preceded by baz:
Search: (?<=baz)foo
Replace: replacement
Lookarounds are supported by most modern regex engines including JavaScript's.
Practical example: API migration
Your team is migrating from /api/user?id=123 query-param style to /api/users/123 path style.
Search: /api/user\?id=(\d+)
Replace: /api/users/$1
The ? is escaped (\?) because ? is a regex metacharacter meaning "zero or one of the preceding." \? matches the literal question mark in the URL. \d+ captures one or more digits, which becomes $1 in the replacement.
/api/user?id=42 → /api/users/42
/api/user?id=1001 → /api/users/1001
/api/user?id=0 → /api/users/0
Test your pattern with the RegExp Tester before running a replace on the full file — a bad regex in replace mode edits the wrong text across every occurrence.
The $$ escape in replacements
In the replacement string, $ introduces a backreference. To insert a literal $ in the output, use $$. This comes up when adding currencies:
Search: price: \d+\.\d{2}
Replace: price: $$&
$& in the replacement string inserts the entire matched text. $$ outputs a literal dollar sign.
Use the Find and Replace Text for batch edits across code, config files, or data. Always preview matches before replacing, and test your pattern on a small sample first.