The engine, the flags, and the limits you are working inside
A regex tester is a sandbox that compiles your pattern with a real regular-expression engine and runs it against sample text, showing every match, its position, and its capture groups as you type.
Regular expressions fail quietly. A pattern that looks right will match nine sample strings and then quietly accept a tenth it should have rejected, or take a minute to fail on a line of user input. Reading a pattern is not a reliable way to verify it; running it against text you actually expect is.
This tester compiles with your browser’s own ECMAScript engine, which means what you see here is exactly what JavaScript and Node will do with the same pattern. The sections below cover the flags, the safety limits, the substitution syntax, and the dialect differences that catch people out when they port a pattern to Python or PHP.
Concrete facts about this sandbox
- Engine
- Your browser’s native RegExp — the ECMAScript dialect. Patterns are written without wrapping slashes, so enter \d+ rather than /\d+/g and set flags separately.
- Supported flags
- g, i, m, s, u, y, d and v. Anything else is rejected before compiling, with an explicit message naming the invalid flag.
- Text size cap
- Sample text is capped at 120,000 characters. Beyond that the browser tab becomes unresponsive on backtracking-heavy patterns, so the limit is a guard rather than an arbitrary paywall.
- Match cap
- Up to 800 matches are collected per run and the result is marked truncated past that. Highlighting ten thousand spans is what actually freezes a page.
- Highlighting rule
- Overlapping matches are resolved first-match-wins, and matches are shaded in five rotating colours so adjacent matches stay distinguishable.
- Replace preview
- Uses JavaScript replacement semantics: $1 for numbered groups, $<name> for named groups, $& for the whole match, and $$ for a literal dollar sign.
Patterns worth testing before you ship them
Each of these looks correct until it is run against text that includes the awkward case.
Example 1: The greedy quantifier that swallows the line
Pattern: <.+>
Flags: g
Text: <b>bold</b> and <i>italic</i>1 match:
"<b>bold</b> and <i>italic</i>".+ is greedy: it runs to the last > on the line. Change it to <.+?> for a lazy quantifier — or better, <[^>]+> — and the same text yields four matches. Highlighting makes this visible immediately; reading the pattern rarely does.
Example 2: Named groups for a date
Pattern: (?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})
Flags: g
Text: Renewed 2026-03-14 and 2027-01-02y: "2026"
m: "03"
d: "14"
Replace with $<d>/$<m>/$<y>
→ Renewed 14/03/2026 and 02/01/2027Named groups survive refactoring far better than $1, $2, $3. The group panel lists them per match, so you can confirm the names before wiring them into code.
Example 3: Multiline anchors on a log file
Pattern: ^ERROR\s+(.*)$
Flags: gm
Text: INFO started
ERROR disk full
INFO retry
ERROR timeout2 matches:
"ERROR disk full" → group 1: "disk full"
"ERROR timeout" → group 1: "timeout"Without the m flag, ^ and $ anchor to the whole string and this pattern finds one match at most. Toggling m on and off with real log text is the fastest way to internalise the difference.
Catastrophic backtracking, and other ways a pattern goes wrong
Direct answer: a pattern that nests two quantifiers over overlapping character sets can take exponential time on input that nearly matches. This is the bug class behind a long list of real-world outages.
How to recognise the dangerous shape
Look for a quantifier inside another quantifier where both can match the same characters — (a+)+, (\s*\w+)*, or (.*,)* are the textbook forms. On a string that ends without the required terminator, the engine has to try every possible split before giving up, and the number of splits doubles with each added character.
What it looks like here
Testing (a+)+$ against 30 letter As followed by a ! will hang the run. That is a feature of the demonstration: better to discover it in a sandbox than in a request handler where it becomes a denial-of-service vector.
How to fix it
Make the inner class exclusive so the two quantifiers cannot compete for the same characters — [^"]* instead of .* inside a quoted-string pattern. Anchor the pattern, prefer explicit character classes over the dot, and cap repetition with {1,64} instead of an open-ended +.
The dot does not match newlines by default
Without the s flag, . stops at a line break. Patterns written against a single-line sample often fail on real multi-line input for this reason alone.
Do not use regex to parse HTML or JSON
Both are nested formats; regular expressions cannot count nesting depth. Use a parser — and if you only need to read a payload, the JSON formatter will show you the structure faster than any pattern.
Unicode needs the u flag
Without u, \w means [A-Za-z0-9_] and emoji or accented characters are handled as surrogate halves. Validating names or addresses without the u flag will reject legitimate input from most of the world.
Where a JavaScript pattern stops working in another language
Prototype here, then check these differences before pasting the pattern into a Python, PHP, Java or Go codebase.
| Feature | JavaScript (this tool) | Elsewhere |
|---|---|---|
| Lookbehind | Supported: (?<=…) and (?<!…) | Python’s re requires fixed width; Go’s RE2 does not support it at all. |
| Named group syntax | (?<name>…), referenced as $<name> | Python and PCRE use (?P<name>…) and \g<name> or $1-style backreferences. |
| The s flag | Called dotAll | Python calls it re.DOTALL; PCRE calls the same thing the /s modifier. |
| Backtracking risk | Present — this engine backtracks | Go’s RE2 and Rust’s regex crate are linear-time by construction and simply reject patterns that would backtrack. |
| Unicode properties | \p{L} works only with the u or v flag | Python needs the regex third-party module; PCRE needs UTF mode enabled. |
Everything you type stays in your browser — patterns and sample text are never uploaded. Still, avoid pasting production secrets or personal data into any web page.
A method that produces patterns you can trust
- Start with the simplest pattern that matches one example, then add constraints one at a time.
- Paste in the strings that should NOT match — a validation pattern is only proven by its rejections.
- Add anchors (^ and $) once the body works, otherwise a partial match will read as a pass.
- Test the empty string, a very long string, and one containing a non-Latin character.
- Check the replacement preview before trusting a find-and-replace across a codebase.
- Leave a comment in your code explaining the intent — and re-verify against sample data pulled from real records, which you can shape with the CSV to JSON converter.
How this page is maintained
The 120,000-character text cap, the 800-match cap, the accepted flag set and the first-match-wins highlighting rule were read from this tool’s matching code, not estimated. Dialect differences were checked against each language’s own documentation; behaviour changes between runtime versions, so re-test in your target runtime before shipping.
Written and reviewed by the ToolsRacks editorial team. Last reviewed: .