Free Database Audit: comprehensive health report for your database

Learn More
All dev tools

Regex Tester & Debugger

Test regular expressions live with match highlighting, replace preview and explanations — entirely in your browser. Nothing is uploaded.

  • Runs in your browser
  • No upload, no tracking
  • Free forever
Pattern
//g
Flags:
g Global — find all matchesi Case-insensitivem Multiline — ^ and $ match line boundariess DotAll — . matches newlinesu Unicode
Test Input

How it works

A regex tester compiles a regular expression and runs it against sample text in real time, highlighting every match, listing capture groups and their positions, and previewing find-and-replace — so you can debug a pattern before shipping it into code. This one uses the browser's native ECMAScript engine and runs entirely client-side, so your pattern and test data never leave the page. It is built by JusDB, a managed database operations team, for the pattern-matching work that surrounds logs, queries and data pipelines.

  1. 1

    Write your pattern

    Type a regex into the pattern field. Invalid patterns are flagged inline, and token chips below label each part of the expression on hover.

  2. 2

    Toggle flags

    Switch on g, i, m, s and u as needed — the active flags appear after the closing slash and re-run the match instantly.

  3. 3

    Check matches

    Paste text into the Match tab to see highlighted matches with a count, plus each match's position, value and any named capture groups.

  4. 4

    Preview replace or explain

    Use the Replace tab with $1, $2 or $& to preview a substitution, or the Explain tab for a plain-language breakdown of the pattern.

Frequently asked questions

Is my test text sent anywhere?
No. Patterns are compiled and matched with the browser's native RegExp engine. Your pattern and test text never leave the page.
Which regex flags are supported?
You can toggle g (global), i (case-insensitive), m (multiline), s (dotAll) and u (unicode). The active flags appear after the closing slash of the pattern.
Does it show capture groups?
Yes. Each match lists its position and value, and named capture groups are shown as JSON next to the match. Use $1, $2 or $& in the Replace tab to reference groups.
Why do my matches differ from another tool?
This tester uses the JavaScript regular expression engine, which differs slightly from PCRE, .NET or Python. Lookbehind, named groups and some escapes follow ECMAScript rules.
Can it explain what my pattern does?
Yes. The Explain tab breaks the pattern down into a plain-language description, and a row of colour-coded token chips above the tabs labels each metacharacter, quantifier, anchor, group and character class on hover.
How do I preview a find-and-replace?
Open the Replace tab and type a replacement string. You can reference capture groups with $1, $2 and the whole match with $&, and the preview shows the rewritten text live without altering your test input.

Regular expressions in depth: flags, groups, quantifiers and performance

A pattern that looks correct can still match the wrong thing, miss edge cases, or quietly stall under load. Understanding how flags, groups and quantifiers interact — and how different engines disagree — is what separates a regex that works on your sample from one that holds up in production logs, validation layers and database queries.

Flags change matching semantics, not just convenience

Flags reshape how the engine reads your pattern. g makes matching stateful — it advances lastIndex between calls, so reusing one global regex object across loops can skip matches. i folds case, m makes ^ and $ match at line breaks rather than only string ends, and s (dotAll) lets . span newlines. u enables full Unicode handling so astral code points and \p{Letter} property escapes behave correctly. Combine them deliberately: enabling m without realizing it can turn an anchored whole-string validation into a per-line match and let malformed input slip through.

Groups, backreferences and the cost of capturing

Plain (...) captures and numbers each group left to right; (?:...) groups without capturing, which keeps your match array clean and is marginally cheaper. Named groups (?<year>\d{4}) make extraction self-documenting and are referenced as \k<year> inside the pattern or $<year> in a replacement. Backreferences like \1 let a pattern match the same text twice — handy for catching doubled words — but they prevent the engine from using simpler linear-time matching, so reach for them only when you truly need them.

Greedy vs lazy quantifiers and catastrophic backtracking

Quantifiers are greedy by default: .* grabs as much as possible then backtracks. Adding ? makes them lazy (.*?), matching the minimum first. The dangerous case is nested or overlapping quantifiers over ambiguous input — patterns like (a+)+$ or (\d+)* against a long non-matching string force the engine to explore exponentially many ways to split the text. This is catastrophic backtracking, and on a server it is a real denial-of- service vector (ReDoS): one crafted input can pin a CPU core for seconds. Avoid it by anchoring patterns, preferring specific character classes over ., avoiding a quantifier inside another quantifier, and validating untrusted input length before matching.

Anchors, boundaries and engine flavors

^ and $ anchor to string (or line) edges, while \b marks a word boundary — the seam between a word and non-word character — which is what you usually want for matching whole words rather than ^word$. Flavors also diverge: this tester runs the JavaScript (ECMAScript) engine, so its lookbehind, Unicode property escapes and named-group syntax follow ES rules and will not always agree with PCRE (PHP, the pcre library), POSIX (grep, sed basic mode) or Python's re. Before copying a pattern into another runtime, re-test it there. When a pattern matches in one place but not another, the diff checker helps spot the stray whitespace or invisible characters that quietly break a match.

Regex inside database queries

Databases speak regex too. PostgreSQL offers the ~ and ~* operators (case-sensitive and insensitive) plus SIMILAR TO, while MySQL uses REGEXP / RLIKE. The catch is performance: a B-tree index can only help when a predicate is anchored to a known prefix, so col >= 'abc' style comparisons use the index but col ~ 'abc' or any pattern with a leading wildcard forces a full scan and evaluates the regex row by row. For high-volume filtering, normalize the data, use a prefix predicate, or add a trigram index (Postgres pg_trgm) instead of leaning on a heavy expression in the WHERE clause. See our PostgreSQL guide for indexing strategy that keeps pattern matching off the hot path.

Quick gut check before you ship a pattern: anchor it, replace any .* you can with a precise class, make sure no quantifier wraps another, and test it against a long string that should not match — if matching feels slow on that input, you have a backtracking problem to fix now, not in production.