Regex Tester (JavaScript)
Test JavaScript regular expressions live — highlighted matches, groups and replace preview, entirely on this device.
Drop a text file on the test string pane — it is read on this device and never uploaded.
Native JavaScript replace semantics — the preview pane below updates as you type.
Pattern history
Patterns you run appear here — stored only on this device, never test strings.
Press ? for shortcuts
Do it offline:$ node -p 'require("fs").readFileSync(0,"utf8").match(/\d{4}-\d{2}-\d{2}/g)' < app.log
How to use it
- Type the pattern without delimiters — just what sits between the slashes.
- Tick flags as needed; each checkbox has a one-line hint, and g finds all matches instead of the first.
- Paste test text, or drop a .txt or log file — read locally, never uploaded.
- Read matches as badged highlights, or in the table with positions and every capture group.
- Set a replacement template — $1, $<name>, $$ — to open the replace preview.
- Copy the pattern in three code spellings, export matches, or share the state as a link.
Type a pattern and every match lights up as you type — index badge, position, and each numbered or named capture group in a table. Matching runs on your browser's own JavaScript engine inside a worker: the result is exactly what production code will do, and nothing you paste leaves this device. A template field previews replacements; the copy bar emits ready-to-paste code.
How it works
No regex library ships with this page. Your pattern is compiled and executed by the browser's own JavaScript engine — the same RegExp production code calls — so boundaries, captures and replacements are flavor-exact by construction.
Every run happens in a Web Worker under a hard one-second watchdog. Backtracking cannot be interrupted from inside JavaScript, so past the deadline the worker is terminated whole and respawned; your pattern never executes on the main thread.
The canonical runaway is (a+)+$ against aaaaaaaaaaaaaaaaaaaaaaaaaaX: nested quantifiers give exponentially many ways to split the 26 a's, and the final X forces every one to fail. Each character added doubles the search — why the demo stays prose, never a click-to-run example.
Examples
Ada Lovelace ada@example.com
Ops noreply@ithomia.dev
Support support@glasswing.toolsada@example.com
noreply@ithomia.dev
support@glasswing.toolsThe pragmatic address grab /[^\s@]+@[^\s@]+\.[^\s@]+/g — non-space runs around one @, then a dotted tail — not full mailbox validation. The .txt export is exactly these three lines.
deploy 2026-08-06 ok
rollback 2026-08-07 pendingdeploy 06/08/2026 ok
rollback 07/08/2026 pending/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/g names its captures, so the table lists y, m and d with offsets, and $<d>/$<m>/$<y> reads them back. Shown: the replace preview, byte for byte.
12 and 3412/\d+/ carries no flags, so one exec finds 12 and stops before 34; a chip says only the first match is reported — the classic missing-g surprise.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Empty-string matches end, and get counted
a* on bc finds three empty matches at offsets 0, 1 and 2 — iteration advances past empty hits natively, and a chip counts them.
No g means one match; y means anchored
Without g a single exec stops at the first hit, chip included. Sticky y pins that attempt to the start instead of scanning forward.
Multi-MB logs render by viewport
Only the visible slice is painted; the full match list still arrives from the worker. Past 16 MB the tool refuses — truncation would make offsets lie.
\p{…} does nothing without u or v
Property escapes need a Unicode flag. Without one, \p{L} quietly matches the literal text p{L} — a hint chip appears whenever the construct shows up flag-less.
u and v are either/or
v supersedes u: set operations like [\p{L}--[a-z]] plus stricter class rules. The engine rejects the pair, so ticking one disables the other, reason shown.
v needs a 2023-era browser
Chrome 112, Firefox 116 and Safari 17 shipped it. Older engines get a disabled checkbox that says why — the page reports what your engine can do.
Lookbehind stopped being exotic at Safari 16.4
(?<=…) and (?<!…) run everywhere current; Safari landed them last, in 16.4. A pattern that throws only for a teammate usually means an older WebKit.
Error wording belongs to your engine
Browsers phrase the same mistake differently; nothing is rewritten here. A pattern under the 64 KB cap can still be refused by the engine as too large — shown verbatim, like everything else.
Common errors
Invalid regular expression: /a(/: Unterminated group- One engine's phrasing for an unclosed group — you always see your own browser's wording. The bracket is highlighted when derivable; close it, or escape a literal parenthesis as \(.
the u and v flags cannot be combined — pick one Unicode mode- Two generations of one Unicode mode: each pattern picks at most one. The checkboxes enforce it up front; this message is the engine-side guard.
Input is larger than the 16 MB limit for this tool. For bigger payloads use the CLI: node -p 'require("fs").readFileSync(0,"utf8").match(/\d{4}-\d{2}-\d{2}/g)' < app.log- A refusal, never a truncation — the page matches all of your text or none. The quoted one-liner runs the identical flavor in Node at any size.
Stopped after 1 s — this pattern likely backtracks catastrophically on this input.- The watchdog killed the worker; a fresh one takes the next run. Nested quantifiers over the same characters — the (a+)+$ shape — are the usual cause; how-it-works above explains the blow-up.
FAQ
Which regex flavor is this tester checking against?
JavaScript, executed by the engine of the browser you are in — never an approximation. PCRE, Python or Java patterns may need translation: possessive quantifiers and atomic groups are not JavaScript syntax.
Where do my pattern and test text go?
Nowhere — compiling and matching happen in a worker inside this page, no server in the path. Share links live in the URL fragment, which browsers never send with requests; pattern history stays on this device, skipped for credential-shaped input.
What stops a pattern that never finishes?
A one-second watchdog. Runs execute off the main thread; past the deadline the worker is destroyed — the only reliable end to catastrophic backtracking — and respawned. A banner names the cause, not a frozen tab.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the pattern now, skipping the debounce.
- ⌘/Ctrl + S
- Export matches as .txt, one per line (overrides the browser's save dialog).
- ⌘/Ctrl + C
- Copy the pattern as a JS literal while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the JS literal even with a selection active.
- t
- Cycle to the next theme.
- ? or ⌘/Ctrl + /
- Open the shortcut help overlay.
- Esc
- Dismiss the topmost overlay.