Regex Tester
Test regular expressions online for free. Real-time regex matching and highlighting.
Advertisement
Matches highlighted2 found
Match Details
Common Patterns
Regex quick reference
Character Classes
.Any character (except newline)\dDigit [0-9]\wWord char [a-zA-Z0-9_]\sWhitespace[abc]a, b, or c[^abc]Not a, b, or cQuantifiers
*0 or more+1 or more?0 or 1{n}Exactly n{n,m}Between n and m*?Lazy (non-greedy)Anchors & Groups
^Start of string$End of string\bWord boundary(abc)Capture group(?:abc)Non-capturing group(?=abc)LookaheadAdvertisement
How to Use This Tool
Enter Your Regex Pattern
Type your regular expression in the pattern field. The forward slashes and flag fields follow standard regex syntax.
Set Flags
Check the flags you need: g for global (find all matches), i for case-insensitive, m for multiline mode.
Test Against Your String
Enter your test string in the lower field. Matches highlight in yellow instantly as you type. The match list shows all found matches.
Advertisement
Related Tools
Frequently Asked Questions
What is a regular expression?
What do the flags g, i, and m mean?
Why does my regex work in testing but not in my code?
How do I match a literal dot or parenthesis?
About Regex Tester
You are trying to strip PII from a log stream and the SSN pattern you copied from Stack Overflow matches 'Order 123-45-6789-X' when it should not. Or you are writing a Next.js middleware rule and need to prove that /blog/[slug]/comments/[id] matches your intended regex before shipping it to production. This tester runs your pattern through the native JavaScript RegExp engine — the same one Chrome, Firefox, Safari, Node, and Cloudflare Workers use — so there is no false positive where a pattern works here but not in your actual runtime. It shows every match with capturing groups expanded, the flags (g, i, m, s, u, y) you have active, live match-by-match highlighting inside the test string, and a replace mode with $1/$2 backref preview. A sidebar of ten real patterns (email, URL, IPv4, hex color, strong password, credit card) saves you from copy-pasting from SO every time.
How it works
- 1
Native RegExp with user-controlled flags
We construct a new RegExp(pattern, flags) on every keystroke inside a try/catch. If your pattern has an unmatched bracket or invalid quantifier, you see the V8 error message inline instead of a silent failure. All six standard flags are toggleable: g (global), i (case insensitive), m (multiline ^/$), s (dotall), u (unicode), y (sticky).
- 2
Matches enumerated via matchAll
When the g flag is set we use String.prototype.matchAll to iterate every match without mutating the regex's lastIndex. Each result includes the full match, every capturing group, and the starting index in the input. The UI highlights each match position inline and lists groups below so you can see exactly what $1, $2 will expand to in replace mode.
- 3
Replace preview with backref expansion
Toggle replace mode and enter something like 'name: $1, id: $2'. We run input.replace(regex, template) and show the before/after side by side. This is the easiest way to catch accidental $& (whole match) versus $1 (first group) bugs that only surface once you deploy the replacement to production log transforms.
Pro tips
Use the u flag when your input contains emoji or non-ASCII
Without the u (unicode) flag, a pattern like /./ matches each surrogate half of a 4-byte emoji separately, so 'ABC' counts as 5 characters and /.{3}$/ matches the wrong thing. Turn u on for any text that might contain CJK, emoji, or accented Latin. It also unlocks the \u{1F600} syntax for matching specific code points and enables stricter escape validation that catches bugs like /\p/ (typo for \p{L}).
Anchor your validation patterns with ^ and $
A pattern like /[a-z]+@[a-z]+/ will gleefully match 'foo@bar' inside the string 'malicious-input;foo@bar;DROP TABLE'. For validation (as opposed to extraction), always wrap in ^...$ or use the match() result's .index === 0 and .[0].length === input.length to prove the match is the whole string. HTML5 pattern attribute does this implicitly; String.prototype.match does not, and this asymmetry has caused more than one auth bypass.
Prefer atomic groups or possessive quantifiers — except JavaScript does not have them
Catastrophic backtracking on a pattern like /(a+)+b/ against 'aaaaaaaaaaaaaaaaaX' will hang the browser tab for minutes. JavaScript's engine has no built-in protection. Rewrite nested quantifiers to be non-overlapping (/a+b/ is linear, /(a+)+b/ is exponential) and test against a deliberately bad input (30+ repeated characters with no match) here before shipping. Tools like safe-regex can flag obvious ReDoS vulnerabilities but cannot catch subtle ones.
Honest limitations
- · JavaScript regex engine only — no lookbehind-of-variable-length, no recursive patterns, no named backrefs in older browsers. Patterns that work in PCRE or Python's re module may not port directly.
- · No ReDoS protection — a pattern with nested quantifiers can freeze the tab for minutes. Test with short, deliberately-bad inputs first.
- · Match count display is capped around 10,000 matches to keep the DOM responsive; the underlying regex still runs to completion.
Frequently asked questions
Does this use the same regex engine as my Node.js backend?
Yes, assuming your backend runs V8 (Node, Deno, Cloudflare Workers, Bun when using --v8 or default). Bun's default JSC engine has minor differences for some lookbehind cases, and Safari uses JavaScriptCore which differs subtly from V8 on unicode property escapes. For 99% of patterns — character classes, quantifiers, anchors, backreferences — the behavior is identical. If you are targeting a Cloudflare Worker, what works here works there verbatim because Workers run V8.
Why does my pattern with a lookbehind fail?
JavaScript supports lookbehinds only from ES2018 and only in modern browsers. Safari added support in 16.4 (March 2023), so older iOS devices will throw a SyntaxError at parse time. If your regex needs /(?<=prefix)value/, either polyfill with a capture-group-and-discard pattern like /prefix(value)/ and use match[1], or confirm your minimum browser support. Variable-length lookbehinds /(?<=\w+)foo/ work in V8 but not in all engines — stick to fixed-width lookbehinds when shipping broadly.
How do I write a regex that does not catastrophically backtrack?
Avoid overlapping quantifiers. The pattern /(a+)+/ is exponential because the engine can split 'aaaa' into 1+3, 2+2, 3+1, etc. Rewrite so each character is consumed by exactly one quantifier — /a+/ is fine, /a*b+/ is fine, /(a|b)+/ is fine because the alternation is non-overlapping. For complex cases, use the regex-101 debugger to see backtracking step count, or test your pattern against a 50-character string of the bad input that never matches; if it takes more than 100ms, rewrite.
What is the difference between g and y flags?
The g (global) flag lets you iterate every match in the string with matchAll or repeated .exec calls; each match can start anywhere after the previous. The y (sticky) flag requires the next match to start exactly at regex.lastIndex — no skipping over non-matching characters. Sticky is what tokenizers use: you advance lastIndex manually between matches and any gap means the input is malformed. For data extraction use g; for parsing a structured language use y with careful lastIndex management.
Can I export my pattern to Python, Go, or PHP syntax?
Not automatically, but most JavaScript regex translates literally. Python's re module accepts the same character classes, quantifiers, and anchors; the only common divergence is named groups (JS: /(?<name>x)/, Python: (?P<name>x)). Go's regexp package uses RE2 which explicitly does not support backreferences or arbitrary lookaround, so a pattern with \1 or (?=foo) will not compile. PHP's PCRE is the most permissive — anything that works in JavaScript will work there, plus extras like atomic groups that JS lacks.
Regex work usually feeds a larger pipeline. Patterns for parsing JWT claims or structured log payloads pair naturally with the jwt-decoder and json-formatter — validate structure first, then extract fields. When redacting base64-encoded secrets from logs, the base64-encoder is the quickest way to check whether your pattern's captured string is a valid encoding or just lookalike alphanumerics. For matching scheduled job identifiers like 'run_2026-04-14T03:00' inside Kubernetes logs, iterate the pattern here then paste the cron expression that produced those identifiers into the cron-generator to verify the schedule is what you expected.
Advertisement