Regex Replace Tool
Quick Access to Regex Tools
Go straight to the regex utility you need.
How to Use the Regex Replace Tool
Enter your regex pattern
Enter your regex pattern.
Set the replacement string
Set the replacement string.
Paste the source text
Paste the source text.
Preview and apply the replacements
Preview and apply the replacements.
Regex Replace Tool — Find and Replace with Regular Expressions
A simple find-and-replace can handle exact strings, but real text doesn't play by exact rules. Dates show up in five different formats in the same document. Phone numbers have parentheses in some entries and dashes in others. Names appear with inconsistent spacing or capitalization. Regex replace solves these problems by matching patterns instead of literals — and then transforming the matched text with surgical precision using capture groups and backreferences.
Paste your text, write a pattern, and specify the replacement. The tool shows you exactly what changed, with the original and transformed text side by side.
Capture Groups and Backreferences Explained
Capture groups are portions of your pattern wrapped in parentheses. Each group captures a piece of the matched text that you can reference later. In your replacement string, $1 refers to the first capture group, $2 to the second, and so on. This is where the real power of regex replace lives — you're not just swapping text, you're reordering and reshaping it.
For example, to swap the first and last names in John Smith, use the pattern (\w+)\s(\w+) with the replacement $2, $1. The first group captures "John", the second captures "Smith", and the replacement puts them in reverse order with a comma: Smith, John. You can also reuse the same group multiple times — $1 $1 would double the first name.
The numbering of capture groups is always left-to-right based on opening parentheses. Nested groups count too — ((\w+)\s(\w+)) creates three groups where $1 is the entire match, $2 is the first word, and $3 is the second word. Non-capturing groups (?:...) are skipped in the numbering. If you have (\w+)(?:\s+)(\w+), the first and second capturing groups are still $1 and $2 despite the non-capturing group in between.
Lookaround Replacements
Lookarounds let you match or skip text based on what comes before or after it — without including that surrounding text in the match or the replacement. This is incredibly useful when you want to transform a specific token but leave its context untouched.
Positive lookahead (?=...) asserts that a pattern follows but doesn't consume it. To insert a space before every uppercase letter in a camelCase string, use ([a-z])([A-Z]) and replace with $1 $2. This turns myVariableName into my Variable Name without losing any characters.
Negative lookahead (?!...) asserts that a pattern does NOT follow. To replace all occurrences of http with https — but only when not already followed by s — use http(?!s) and replace with https. Without the negative lookahead, you'd double the s in URLs that already use HTTPS.
Positive lookbehind (?<=...) asserts that a pattern precedes the match. To extract only the digits after a dollar sign, you could use (?<=\$)\d+. The lookbehind ensures the digits are preceded by $ without including the dollar sign in the capture. This is cleaner than capturing the dollar sign and removing it in a second step.
Negative lookbehind (?<!...) asserts that a pattern does NOT precede the match. To replace all periods that aren't part of an abbreviation, use \.(?![A-Z]) and replace with ! — this targets periods followed by lowercase letters or end-of-string while leaving e.g. and Dr. alone.
Lookarounds have a key constraint: lookbehinds must be fixed-length in some regex engines. Python's re module, for instance, doesn't support variable-length lookbehinds. JavaScript supports variable-length lookbehinds as of ES2018. PCRE (used in PHP) supports them. Always check your target engine's capabilities before relying on lookbehinds with flexible patterns.
Conditional Replacements
Sometimes you want the replacement to depend on what was matched. While static replacement strings can't do this directly, most programming languages support callback-based replacements that make conditional logic possible.
In JavaScript, str.replace(/(\d+)/g, (match) => parseInt(match) > 100 ? 'large' : 'small') replaces numbers conditionally based on their value. In Python, re.sub(pattern, lambda m: 'yes' if 'error' in m.group().lower() else 'no', text) evaluates a condition for each match. These callback approaches are the standard way to implement conditional replacements when a static replacement pattern isn't flexible enough.
For simpler conditional logic, you can sometimes use alternation within the pattern itself. The pattern (Windows|Linux|MacOS) matches all three OS names, and you can replace each with a standardized version using separate passes or a callback that maps each match to its replacement.
Backreferences: Using What You Matched
Backreferences in the search pattern (distinct from backreferences in the replacement) let you match text that was already captured earlier in the pattern. The pattern (\w+)\s+\1 matches any word that appears twice consecutively — like "the the" or "is is". The \1 inside the pattern refers back to whatever (\w+) captured.
This is invaluable for finding duplicate words, repeated phrases, or any pattern where the same text appears in two positions. To fix doubled words automatically, match (\b\w+\b)\s+\1\b and replace with $1 — the backreference in the pattern finds the duplicate, and the backreference in the replacement keeps only the first occurrence.
Be careful: backreference numbering in the search pattern counts the same groups as backreference numbering in the replacement. They refer to the same capture groups. If you use \1 in the pattern and $1 in the replacement, both point to the first capture group.
Practical Replacement Scenarios
Reformatting dates: Convert 2024-01-15 to January 15, 2024 by capturing the year, month, and day with (\d{4})-(\d{2})-(\d{2}) and replacing with $2/$3/$1 for a simpler MM/DD/YYYY format. For more complex transformations (converting month numbers to names), you'd typically use a programming language with a callback function rather than a static replacement.
Anonymizing sensitive data: Replace email addresses with [REDACTED] using [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}. Mask credit card numbers by matching \b(\d{4})[- ]?(\d{4})[- ]?(\d{4})[- ]?(\d{4})\b and replacing with $1-XXXX-XXXX-$4 — showing only the first and last four digits.
Cleaning text: Remove extra whitespace with \s{2,} replaced by a single space. Strip HTML tags using <[^>]+> replaced with empty string. Normalize line endings by matching \r?\n and replacing with \n. Remove leading/trailing spaces from each line with ^\s+|\s+$ in multiline mode.
Standardizing identifiers: Convert myVariableName to my_variable_name (camelCase to snake_case) by matching ([a-z])([A-Z]) and replacing with $1_$2. Convert user_name to userName (snake_case to camelCase) by matching _([a-z]) and replacing with the uppercase version of the captured letter. These transformations are common in cross-language development where naming conventions differ.
Restructuring data fields: When working with CSV or delimited data, regex replace can reorder columns. If you have Last, First and want First Last, match ([^,]+),\s*(.+) and replace with $2 $1. For tab-separated data, replace the tab character with commas, or vice versa, using simple literal replacement.
Multi-Step Replacements
Complex text transformations often require multiple sequential replacements rather than a single pattern. The key principle is to handle one concern per step, progressing from broad to specific.
Step 1: Normalize whitespace. Replace \s{2,} with a single space. This handles tabs, multiple spaces, and inconsistent spacing in one pass. Step 2: Fix line endings. Replace \r?\n with \n to normalize Windows and Mac line endings. Step 3: Apply domain-specific transformations. Now that the text is clean, apply your pattern to restructure, anonymize, or reformat the content.
This layered approach is more reliable than trying to do everything in a single complex pattern. Each step is independently testable and debuggable. If something goes wrong, you can identify exactly which transformation caused the issue by inspecting the output after each step.
When chaining replacements, be aware that later steps can undo the work of earlier ones. If Step 1 removes all double spaces, and Step 2 introduces them again, you've got a problem. Design your steps to be idempotent where possible — running the same step twice should produce the same result as running it once.
Common Replacement Patterns to Keep Handy
Non-capturing groups: Use (?:...) when you need grouping for quantifiers but don't want to capture the content. This keeps your backreference numbering clean. In (\d{4})-(?:0[1-9]|1[0-2])-(\d{2}), only the year and day are captured — the month is matched but not stored.
Named groups: Some engines support (?<name>...) syntax for named capture groups, making replacements more readable. Instead of $1, $2, you'd use $name, $day. This tool uses numbered backreferences, which work across all regex flavors.
Literal dollar signs: If your replacement text needs a literal $ (like a price string), escape it as $$. Without escaping, the engine tries to interpret it as a backreference.
Tips for Reliable Replacements
Always test your pattern with the g flag first. Without it, only the first occurrence gets replaced — a common source of incomplete transformations. Use the m flag when anchors need to operate on individual lines. Before running a replacement on a large document, test it on a small sample that includes edge cases: empty lines, Unicode characters, and boundary conditions at the start and end of the text.
When a replacement produces unexpected results, the issue is usually one of two things: the pattern is too broad (matching more than intended) or the backreference numbering is off. Count your parentheses carefully, keeping in mind that each opening ( increments the group counter regardless of whether it's a capturing or non-capturing group.
Another common pitfall is greedy vs. lazy quantifiers affecting the replacement scope. A pattern like <.*> matches from the first < to the last > on the line (greedy), which might match more than you intended. Switching to <.*?> (lazy) makes it match the shortest possible string. For HTML tag removal, the lazy version is almost always what you want — it matches individual tags rather than everything between the first opening and last closing tag on a line.
Frequently Asked Questions
$1, $2, $3, etc. to reference the first, second, and third capture groups from your pattern. For example, the pattern (\w+)@(\w+)\.(\w+) with replacement $1 at $3.$2 transforms [email protected] into user at com.company. The groups are numbered left-to-right by opening parenthesis. Non-capturing groups ((?:...)) don't count toward the numbering.String.prototype.replace() with a function, Python's re.sub() with a callable) that let you apply .toUpperCase() or equivalent to captured groups. For simple transformations, you can chain multiple replacements — first capture what you need, then transform it in a second pass.$$. A single $ in the replacement string is treated as the start of a backreference. So $100 is interpreted as group 1 followed by literal "00", not as the literal text "$100". Write $$100 instead to produce the literal string "$100".555-123-4567, match (\d{3})-(\d{3})-(\d{4}) and replace with $1$2$3. The parentheses capture only the digits, and the replacement concatenates them without the dashes.g (global) flag. Without it, the replacement only applies to the first match. This is one of the most common mistakes — people write a correct pattern, forget the g flag, and wonder why only the first instance was replaced. For multiline text, also consider adding the m flag if your pattern uses ^ or $ anchors.(?:...) non-capturing groups, they don't count — but plain parentheses do. Also verify that your pattern isn't matching overlapping text. Greedy quantifiers can cause a match to consume characters that you expected to be part of the next match.\s{2,} to a single space, (2) trim leading/trailing spaces with ^\s+|\s+$ in multiline mode, (3) apply your domain-specific transformations. Each step handles one concern cleanly rather than trying to do everything in a single complex pattern.$ (for backreferences) and \ (for escaping). Everything else — dots, asterisks, brackets — is treated as literal text. To insert a literal $, write $$. To insert a literal \, write \\. Unlike the search pattern, replacement strings don't interpret character classes or quantifiers.(?<=\$)\d+ matches digits that follow a dollar sign. A negative lookahead like http(?!s) matches http only when it's not already followed by s. This is useful for replacements where you need to transform a specific token but only when it appears in a particular context — and you don't want the surrounding text affected by the replacement.\b(\w+)\s+\1\b and replace with $1. The backreference \1 in the pattern ensures the second word is identical to the first. The replacement $1 keeps only the first occurrence. For example, "the the quick brown fox fox" becomes "the quick brown fox". Note that this only catches exact consecutive duplicates — it won't catch "the very very" (with a word between) or case-insensitive duplicates like "The the".