Free Regex Tester — Debug & Match Patterns Online
Test regex patterns instantly against any text. Live match highlighting, capture groups, replace preview, split, and pattern explainer. JavaScript-flavor regex, 100% private, no signup.
What Is a Regex Tester?
A regex tester (regular expression tester) is a tool that lets you write a regex pattern, paste a piece of test text, and see exactly what the pattern matches — with capture groups, replacement preview, and a flag breakdown — without recompiling code or running a script. For developers, it shortens the loop from minutes to milliseconds: tweak the pattern, watch the highlights move, ship the regex with confidence.
A regular expression is a compact language for describing text patterns. `\d+` matches one or more digits. `[A-Za-z_]\w*` matches a typical identifier. `(?
This tester runs the native ECMA-262 RegExp engine that ships in every modern browser — the same engine you call from JavaScript, TypeScript, Node.js, Deno, or Bun. That means: capture groups (numbered and named with `(? What the tester surfaces beyond raw matches: the Matches & capture groups panel lists every match with its [start, end) offsets and each capture group's value — the same information you'd get from `String.prototype.matchAll` with the /d flag, but laid out for visual scanning. The Replace tab shows a live substitution preview supporting the full $1 / $& / $` / $' / $$ / $ For privacy: every operation is local. Your pattern and your test text never leave the page — they aren't logged, aren't sent to an analytics service, aren't stored on disk. Only your UI preferences (active tab + which flags you usually have on) persist to localStorage. That makes this tool safe for redacted log samples, proprietary patterns, internal config, and patterns that include hints about your data schema. Compared to server-backed testers like regex101, the privacy and latency story is strictly better; the trade-off is single-flavor support (JavaScript only). If you're new to regex, the Common patterns dropdown ships with battle-tested starters: email address, URL, IPv4, UUID, hex color, ISO date, US phone number, and a trim-trailing-whitespace pattern. Load one, observe the matches against the supplied sample text, then mutate the pattern one character at a time to feel how the engine responds. Pair this with the Text Diff tool when you want to compare before/after of a regex-driven cleanup, with JSON Formatter when your input or expected output is JSON, or with URL encoder when the strings you match are URL-encoded.
// The pattern you build in this tester drops straight into JavaScript.
// Example: extract every ISO date from a string with named groups.
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g;
const text = 'shipped 2026-05-21, scheduled 2026-06-30';
for (const m of text.matchAll(pattern)) {
console.log(m.groups.year, m.groups.month, m.groups.day);
// → 2026 05 21
// → 2026 06 30
}
// Same regex, used in a replace with $<name> templates:
text.replace(pattern, '$<day>/$<month>/$<year>');
// → 'shipped 21/05/2026, scheduled 30/06/2026'
// With the /d flag, every match carries [start, end] indices
// per capture group — the Matches panel uses this to paint offsets.
const p2 = /(?<year>\d{4})-(?<month>\d{2})/gd;
const m = [...text.matchAll(p2)][0];
m.indices.groups.year; // [8, 12] Key Features
Live Match Highlighting
Every match in your test text lights up the instant your pattern parses. Alternating colours make adjacent matches easy to count visually, and the count badge above the result tells you the exact total — no Run button, no debounce delay over 200ms.
Capture Groups Side Panel
The Matches & capture groups panel on the right lists each match as a card with its [start, end) offsets, the full match text, and every positional + named capture group inside it. Named groups label themselves as $
Live Replace Preview with $1 / $& / $
Switch to the Replace tab to see your substitution applied in real time. The full ECMAScript replacement alphabet works: $1..$N for positional, $
Split with Regex Boundaries
The Split tab calls String.prototype.split with your regex and shows every part as a numbered list. Empty parts are rendered with a ⏎ glyph so you can see how the engine handled adjacent delimiters — useful for debugging CSV-like input cleanup.
Pattern Explainer (Token-by-Token)
The Explain tab tokenises your pattern into chips coloured by class (escape / quantifier / character class / group / anchor / alternation) and annotates each chip with a one-line description. Read your own regex back to yourself before shipping; use it for code review or teaching.
ReDoS-Safe (Wall-Clock Timeout)
Every match call is wrapped in a 250-millisecond budget. Classic catastrophic-backtracking shapes like `(a+)+`, `(a|aa)+b`, and deeply nested quantifiers abort cleanly with a Pattern timed out warning — the page stays responsive instead of locking the tab. Detection without a server-side sandbox.
Common Patterns Library
Battle-tested starters for the eight patterns developers reach for most: email, URL, IPv4, UUID v4, hex color, ISO date, US phone number, and trim-trailing-whitespace. Each loads with a matching sample so you see the regex working before you adapt it.
Permalink Sharing (No Upload)
Copy link encodes pattern + flags + sample text into the URL hash (#p=…&f=gim&t=…). Browsers never transmit URL fragments in requests, so a shared link reproduces your state on the recipient's machine without touching go-tools.org servers. Self-contained, audit-friendly.
100% Private, Browser-Only
Your regex and test text never leave your device. No network requests, no logging, no analytics on what you type. Verify in DevTools → Network: zero requests when you type. Safe for proprietary patterns, redacted logs, and any text you wouldn't paste into regex101.
Worked Examples
Extract every email address from a paragraph
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g Paste the pattern with the /g flag on, drop a paragraph into the test text, and every email lights up in the highlighted view. The Matches & capture groups panel on the right lists each address with its [start, end) offsets — useful when piping the same regex into grep, sed, or a code editor.
Capture date parts with named groups
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g ECMA-262 named groups appear in the right panel as $
Find/replace with $1 back-references
(\w+) (\w+)
Replacement: $2, $1 → Jack Doe → Doe, Jack
Two unnamed capture groups, replacement template $2, $1, and the Replace tab gives you a live preview. $&, $`, $', $$, and $
Strip trailing whitespace line by line
[ \t]+$
/[ \t]+$/gm
Combine the /g (global) and /m (multiline) flags so $ anchors at every line end, not just the end of input. The Replace tab with an empty replacement preview shows a clean diff: trailing tabs and spaces vanish, the prose stays put. The same regex with the /s (dotAll) flag off keeps . from crossing newlines.
Detect catastrophic backtracking and survive it
(a+)+b
Test text: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
The nested + quantifiers form a classic ReDoS pattern. In a naive tester this hangs the tab. Here the wall-clock guard fires after 250ms, the Pattern timed out banner appears, and the page stays responsive. Anchor the pattern, switch to a non-overlapping alternation, or use atomic-like idioms — and re-test.
Split a CSV-like line by mixed delimiters
[,;|]\s*
alpha, beta; gamma | delta → ["alpha", "beta", "gamma", "delta"]
Switch to the Split tab. Any comma, semicolon, or pipe (followed by optional whitespace) becomes a part boundary. Useful for cleaning copy-pasted tag lists, normalising user input, or pre-processing log fields before a real CSV parser — see CSV to JSON when the data really is RFC 4180.
How to Use the Regex Tester
- 1
Type your pattern between the slashes
Drop any ECMA-262 regular expression into the /…/ field. Bad patterns highlight in red with a parser message; valid patterns proceed to live matching.
- 2
Toggle the flags you need
g (global), i (case-insensitive), m (multiline), s (dotAll), u (unicode), y (sticky), d (indices). Each chip lights up when on; the readout right of the pattern shows the canonical literal.
- 3
Paste your test text
Matches highlight in alternating colours as you type. The Matches & capture groups panel on the right lists every match with [start, end) offsets and each capture group's value (named groups labeled $
). - 4
Switch tabs for Replace, Split, or Explain
Replace previews a substitution template alongside the input. Split slices on every match boundary. Explain breaks the pattern token-by-token with a plain-English description per element.
- 5
Copy the literal or share a permalink
Copy /pattern/flags drops the canonical regex literal on your clipboard for direct use in JavaScript / TypeScript / Node. Copy link encodes the full state into a URL hash (no upload) so a colleague can reproduce it locally.
Common Regex Mistakes
Forgot the /g flag and only got one match
Without /g (or /y), the engine stops after the first match. The match, matchAll, replace, and split methods all behave differently around the global flag. Toggle /g and re-run; the count above the results jumps from 1 to N.
Pattern: /\d+/ → '1 22 333' yields only ['1']
Pattern: /\d+/g → '1 22 333' yields ['1', '22', '333']
Greedy quantifier consumed too much
`.+` consumes as much as possible, so `<.+>` against ` and ` captures ` and `, not ``. Use lazy quantifiers (`.+?`), more restrictive character classes (`[^>]+`), or anchor with lookarounds.
Pattern: /<.+>/ → matches '<a> and <b>'
Pattern: /<[^>]+>/ → matches '<a>' and '<b>' separately
Catastrophic backtracking from nested quantifiers
`(a+)+b` against a long failing string explodes exponentially. The Pattern timed out banner fires after 250ms; rewrite to remove nesting: `a+b` does the same job in linear time. Atomic-group simulation `(?=(a+))\1b` is another option.
Pattern: /(a+)+b/ on 'aaaaaaaaaaaaaaaaaaaaac' → timeout
Pattern: /a+b/ on the same input → instant 'no match'
Anchors $ and ^ don't behave like Python's \A and \Z
In JavaScript, `^` and `$` mean line-start / line-end ONLY when /m is on; otherwise they mean string-start / string-end. Python's `\A` and `\Z` (which always mean string boundaries) don't exist in JS. Toggle /m as needed.
Pattern: /^Error/ on a multi-line log without /m → matches only first line
Pattern: /^Error/m on the same input → matches every line starting with Error
Used $1 in a string but called replace with a function
`text.replace(re, '$1')` expands the back-reference. `text.replace(re, () => '$1')` passes a literal string '$1' because functions don't see template tokens. Inside the function, capture groups arrive as positional arguments.
text.replace(/(\w+)/, m => '$1') → yields literal '$1'
text.replace(/(\w+)/, (_, g1) => g1.toUpperCase()) → uses the capture
Unicode characters not matching with \w or .
Default `\w` is `[A-Za-z0-9_]`. To match every letter in every script, enable /u and switch to `\p{Letter}` (`\p{L}`). The dot also stops at newlines by default — use /s (dotAll) when you want a true any-character.
Pattern: /\w+/ matches 'hello' but not 'héllo' or '你好'
Pattern: /\p{Letter}+/u matches all three Pasted a PCRE pattern; got a SyntaxError
JavaScript doesn't support atomic groups `(?>...)`, possessive quantifiers `a++`, inline modifiers `(?i)`, conditionals `(?(1)yes|no)`, or `\A` / `\Z`. The parser error names the offending construct — rewrite to the JS-supported equivalent (lookaround simulation, separate flag toggle, alternation).
Pattern: (?i)foo → SyntaxError: invalid group
Pattern: foo with /i flag toggled on → same effect
Who Uses This Tool
- Validate Form Inputs Before Shipping
- Confirm your email / phone / postcode / username regex matches what you expect — and rejects what you don't — across edge cases (unicode names, plus-aliasing, international formats) before the validation reaches production and bounces real users.
- Extract Data from Logs and Configs
- Build a pattern that pulls request IDs, status codes, latencies, or stack-trace lines out of an arbitrary log slice. Named groups make the data self-documenting; the Matches panel shows offsets so you can pipe the same regex into `rg --replace` or `grep -oE` afterwards.
- Find/Replace Across a Codebase
- Draft a refactor pattern (e.g. `(\w+)\.apply\(null,\s*\[(.*?)\]\)` → `$1($2)`) here, preview the substitution against representative snippets, then paste the validated regex into your editor's project-wide find/replace with confidence.
- Sanity-Check a Pattern Found Online
- Pasted a regex from StackOverflow or a blog? Drop it into the Explain tab — every token gets annotated in plain English. Catches subtle issues (`.+?` where you wanted `.+`, missing `^`/`$` anchors, accidentally greedy quantifiers) before the regex lands in your code.
- Teach Regex to a Teammate
- Open the Explain tab on a working pattern and walk through it token-by-token. The colour coding (escape / quantifier / character class / group / anchor / alternation) lets the learner see the structural shape of the regex, not just the characters.
- Port a Pattern Between Languages
- Have a Python or PCRE regex you need to use in JavaScript? Paste it here. If it parses, the explainer shows you the JS-equivalent semantics; if it doesn't, the parser error names the offending construct (atomic groups, possessive quantifiers, inline `(?i)`) so you know exactly what to rewrite.
- Debug a Slow Production Regex
- If a server regex is suspected of catastrophic backtracking, paste it into this tester with a sample of the input. The 250ms wall-clock guard fires on pathological cases, giving you an immediate diagnosis before you reach for profiler tooling — and the explainer points at the nested-quantifier root cause.
Engine & Algorithm Notes
- ECMA-262 RegExp Engine (Native Browser)
- Uses `new RegExp(pattern, flags)` and the engine that ships with V8 / JavaScriptCore / SpiderMonkey — the same regex semantics you get in JavaScript anywhere. Patterns that validate here run unchanged in Node.js, Deno, Bun, and every modern browser.
- Match Iteration via String.matchAll
- Global iteration uses `text.matchAll(regex)` rather than a manual lastIndex loop, so every match carries its capture groups, named groups, and (with /d) [start, end] indices. Zero-width matches are handled with the standard +1 lastIndex advance to avoid infinite loops.
- Wall-Clock Timeout for ReDoS Protection
- A 250-millisecond budget wraps every match, replace, and split call. The engine can still backtrack internally on a single match attempt, but the outer iteration cooperates with the budget — pathological patterns abort with `timedOut: true` and the UI surfaces a warning instead of locking the tab.
- Replacement-Template Reimplementation
- The Replace tab parses $1..$N, $&, $`, $', $$, and $
manually instead of delegating to `String.replace`, so the preview behaves identically across engines (older Safari, older Node) where named-group templates have edge cases. The output is exactly what current JavaScript engines produce. - Pattern Tokenizer for the Explainer
- The Explain tab runs a hand-written tokenizer that classifies each pattern fragment (escape / metachar / quantifier / character class / group-open / group-close / anchor / alternation). Unfamiliar constructs fall through to `literal` with a generic note so the explainer never silently drops content.
- Permalinks via URL Hash (Never Transmitted)
- Share state is encoded in the location.hash fragment (`#p=…&f=…&t=…&tab=…`). Browsers never transmit the fragment in HTTP requests, so go-tools.org servers receive zero data when a permalink is opened. The hydration happens entirely on the recipient's device.
Regex Best Practices
- Anchor Patterns When You Mean To
- `^pattern$` matches an exact string; `pattern` matches anywhere. The wrong choice is the most common bug in form validation: missing `^` lets a leading `attacker.com/` slip past a domain check; missing `$` lets trailing garbage through. Use the Match tab against deliberately broken samples to confirm what's rejected.
- Prefer Non-Capturing Groups for Pure Structure
- `(?:foo|bar)+` and `(foo|bar)+` are functionally identical, but the first one doesn't allocate a capture group. Reach for `(?:…)` whenever the group exists only for a quantifier or alternation — keeps your numbered $1..$N stable and saves a tiny amount of engine work.
- Use the /u Flag for Anything Beyond ASCII
- Without /u, the dot and `\w` treat surrogate-pair characters (emoji, non-BMP code points) as two UTF-16 units. With /u, they're one code point each — what your users will perceive. /u also enables `\p{Letter}` and other property escapes. Default to /u for new patterns unless you have a specific reason not to.
- Name Your Capture Groups
- `(?
\d{4})-(? \d{2})` is self-documenting. Six months later when you read the regex back, `m.groups.year` is obviously the year — `m[1]` is not. Replacement templates with $ survive group reordering, too: positional templates break the moment someone adds another group. - Test Failure Cases, Not Just Success
- A regex tester is for the failures. Confirm what your pattern matches, then deliberately mutate the test text to see what it doesn't — leading whitespace, trailing whitespace, missing parts, extra parts, wrong case, mixed scripts. Patterns that pass valid input but accept garbage are the bugs production exposes first.
Frequently Asked Questions
Is my regex or test text sent to your server?
What regex flavor does this tester use — PCRE, Python, Java, JavaScript?
What do each of the flags g, i, m, s, u, y, d do?
How do I write capture groups and how do I refer back to them?
How do lookahead and lookbehind work, and what are they good for?
Why does my regex hang the browser, and what is catastrophic backtracking?
How is this regex tester different from regex101.com?
How do I escape special characters like . | ( ) [ ] { } * + ? ^ $ \?
Can I share a regex with a colleague via a link?
Does the tester support Unicode, emoji, and non-Latin scripts?
What's the difference between .match, .matchAll, .replace, and .split with a regex?
Why doesn't my Python or Java regex work here?
Is there a maximum text size or match count?
Related Tools
View all tools →Text Diff & Compare
Text Processing
Compare two texts instantly in your browser. Side-by-side view with inline word-level highlights, unified-diff export, ignore case / whitespace / blank lines. 100% private — your text never leaves your device.
Free Word Counter & Character Count Tool
Text Processing
Count words, characters, sentences, paragraphs, and reading time instantly. Real-time word counter with Twitter, meta description, and Instagram limit checks. Free, private, no signup.
Number Base Converter — Binary, Hex, Decimal & Octal
Conversion Tools
Convert between binary, hex, decimal, octal and any base (2-36) instantly. Free, private — all processing in your browser.
Base64 Decoder & Encoder
Encoding & Formatting
Decode and encode Base64 online for free. Real-time conversion with full UTF-8 and emoji support. 100% private — runs in your browser. No signup needed.
Crontab Generator & Cron Expression Builder
Date & Time
Build, validate, and decode cron expressions in your browser. Live next-run preview in local time or UTC. POSIX 5-field syntax, presets, plain-English description. Free, private, no signup.
CSV to JSON Converter
Encoding & Formatting
Convert CSV to JSON in your browser. RFC 4180, type inference, header row, big-int safe. 100% private, no upload.