In short: what is a regex tester?
A regex tester lets you write a regular expression and instantly see what it matches in a sample of text, with every match and capture group highlighted. This tool goes further: it explains any pattern in plain English, builds patterns visually, ships a searchable library of ready-made patterns, extracts emails, URLs and other data, scans for ReDoS security risks, scores complexity, checks compatibility across seven engines, and generates ready-to-run code for ten languages — all 100% in your browser, with nothing uploaded.
Live tester
Real-time matching with colour-coded capture groups and exact positions.
Plain-English explainer
Every token broken down and described, with a one-line summary.
Pattern library
Dozens of verified patterns for email, URL, IP, date, UUID and more.
ReDoS analyzer
Scan for catastrophic backtracking and score safety 0–100.
Code for 10 languages
Generate runnable JS, Python, Java, Go, Rust, C#, PHP, Ruby & Perl.
Cross-engine check
Compatibility across JS, PCRE, Python, Java, .NET, Go and Rust.
What is a regular expression?
A regular expression — almost always shortened to regex or regexp — is a small, formal language for describing patterns in text. Rather than searching for a single fixed string, you describe a shape: “four digits, a dash, then two digits”, “a token that looks like an email”, or “any word that is immediately repeated”. A regex engine then scans your text and reports every span that fits the description. That single idea powers an enormous range of everyday tasks: validating form input, searching and replacing in an editor, parsing log files, tokenising source code, scrubbing sensitive data and extracting structured values from messy text.
Regular expressions have deep roots in computer science — they describe exactly the class of regular languages that finite automata can recognise — but you do not need any theory to use them well. What matters in practice is understanding the handful of building blocks (literals, character classes, quantifiers, groups and anchors) and how a particular engine combines them. Almost every programming language, database, text editor and command-line tool ships a regex engine, which is why regex is one of the highest-leverage skills a developer can learn: the same pattern you test here will, with minor syntax tweaks, work in JavaScript, Python, Java, Go, your editor’s find box and your shell’s grep.
The Tester tab on this page runs the real, native JavaScript (ECMAScript) engine, so what you see is exactly how the pattern behaves in a browser or in Node.js — not a re-implementation that might drift. As you type, matches highlight live, capture groups are colour-coded, and a panel lists each match with its exact start and end position. Because everything runs locally, you can safely test patterns against confidential logs or proprietary text.
Regex syntax guide: the core building blocks
Every regular expression is assembled from a small set of components. Master these and you can read and write the vast majority of patterns you will ever meet. The most fundamental distinction is between literals — ordinary characters that match themselves — and metacharacters, which have special meaning.
| Construct | Syntax | Matches |
|---|---|---|
| Literal | cat | The exact text “cat” |
| Any character | . | Any single character except newline |
| Character class | [aeiou] | Any one character listed in the brackets |
| Negated class | [^0-9] | Any one character NOT listed |
| Range | [a-z] | Any character in the range a to z |
| Digit shorthand | \d | Any digit (0–9) |
| Word shorthand | \w | A letter, digit or underscore |
| Whitespace | \s | A space, tab or newline |
| Alternation | cat|dog | Either “cat” or “dog” |
The metacharacters that need escaping with a backslash to be matched literally are . ^ $ * + ? ( ) [ ] { } | \. For example, to match a literal price like $19.99 you write \$19\.99 — forgetting to escape the dot is one of the most common beginner mistakes, because $19.99 would also match $19x99. Inside a character class far fewer characters are special, which is why [.+*] matches a literal dot, plus or asterisk without any escaping.
Use the Explainer tab whenever you meet an unfamiliar pattern: it breaks the expression into coloured tokens, labels each one (anchor, class, quantifier, group, lookaround…) and describes it in plain English, then summarises what the whole pattern does in a single sentence. It is the fastest way to learn syntax by example, and the interactive Cheat Sheet tab lets you click any token to load a working example straight into the Tester.
Regex quantifiers: greedy, lazy and possessive
A quantifier says how many times the preceding token may repeat. They are where most of regex’s power — and most of its confusion — lives. The four basic quantifiers are:
| Quantifier | Meaning | Example | Matches |
|---|---|---|---|
| * | Zero or more | ab* | “a”, “ab”, “abbb” |
| + | One or more | ab+ | “ab”, “abbb” (not “a”) |
| ? | Zero or one (optional) | colou?r | “color” or “colour” |
| {n} | Exactly n | \d{4} | Exactly four digits |
| {n,} | n or more | \d{2,} | Two or more digits |
| {n,m} | Between n and m | \d{2,4} | Two to four digits |
By default quantifiers are greedy: they match as much as they possibly can, then give characters back (backtrack) only if the rest of the pattern fails. Add a ? after any quantifier to make it lazy (non-greedy), so it matches as little as possible. The classic illustration is matching HTML tags in <a><b>:
Greedy: <.+> → matches "<a><b>" (everything between first < and last >)
Lazy: <.+?> → matches "<a>" then "<b>" (stops at first >)
Better: <[^>]+> → matches "<a>" then "<b>" (cannot cross a >)Notice the third line: replacing the greedy dot with a negated character class [^>]+ is usually the best fix, because it physically cannot cross the boundary you care about and avoids backtracking entirely. Some engines (PCRE, Java) also offer possessive quantifiers (a++) and atomic groups ((?>…)) that refuse to backtrack at all — powerful tools for performance and ReDoS-resistance, though JavaScript supports neither. The Analyzer tab tells you when your pattern uses a construct that will not port to another engine.
Capture groups explained
A capture group is any part of a pattern wrapped in parentheses. Beyond simply grouping tokens so a quantifier applies to all of them, a capturing group remembers the text it matched so you can extract it, reference it later in the same pattern, or use it in a replacement. Groups are numbered from left to right starting at 1, and the entire match is group 0.
Pattern: (\d{4})-(\d{2})-(\d{2})
Input: 2026-06-20
Group 0: 2026-06-20 (the whole match)
Group 1: 2026 (year)
Group 2: 06 (month)
Group 3: 20 (day)Numbered groups get unwieldy fast, so prefer named groups with the syntax (?<name>…). The pattern (?<year>\d{4})-(?<month>\d{2}) is self-documenting, and you can reference the captures by name in replacements ($<year>) and in code. When you only need parentheses for grouping and do not want to capture, use a non-capturing group (?:…) — it is marginally faster and keeps your group numbers tidy.
| Group type | Syntax | Use it when |
|---|---|---|
| Capturing | (…) | You need the matched text afterwards |
| Named | (?<name>…) | You want self-documenting, readable captures |
| Non-capturing | (?:…) | You only need grouping for a quantifier or alternation |
| Backreference | \1 or \k<name> | You need to match the same text again |
Backreferences are where groups become genuinely clever. (\w+)\s+\1 matches a doubled word like “the the” by requiring the same text captured in group 1 to appear again, and (["']).*?\1 matches a quoted string that closes with whichever quote character it opened with. Every match card in the Tester lists all of its groups — numbered and named — with their captured value and exact position, so you can verify your captures at a glance. Note that the linear-time RE2 engines used by Go and Rust deliberately omit backreferences.
Lookaheads and lookbehinds
Lookarounds are zero-width assertions: they check whether text matches at the current position without consuming any characters. That makes them perfect for expressing conditions — “followed by”, “not preceded by” — without including the context in the match itself. There are four:
| Assertion | Syntax | Meaning | Example |
|---|---|---|---|
| Positive lookahead | (?=…) | Followed by … | \d+(?=px) → digits before “px” |
| Negative lookahead | (?!…) | NOT followed by … | \d+(?!px) → digits not before “px” |
| Positive lookbehind | (?<=…) | Preceded by … | (?<=\$)\d+ → number after “$” |
| Negative lookbehind | (?<!…) | NOT preceded by … | (?<!\$)\d+ → number not after “$” |
Lookaheads shine for multi-condition validation. A strong-password rule such as ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$ stacks several lookaheads, each asserting “contains at least one of this category somewhere”, then finally consumes the eight-plus characters. Because each lookahead is zero-width, they all examine the string from the same starting point, which is exactly what “the password must contain a digit and an uppercase letter and…” requires.
A particularly elegant technique is the tempered negative lookahead for exclusions: ^(?!.*foo)\w+$ matches a word that does not contain “foo” anywhere. JavaScript supports variable-length lookbehind, which many engines (notably Java and older PCRE) restrict to a fixed length — another portability difference the Analyzer flags. RE2-based engines (Go, Rust) omit lookarounds entirely to guarantee linear-time matching.
Regex performance optimization
A well-written regex is extremely fast; a careless one can be catastrophically slow on the wrong input. The single biggest performance trap is backtracking — the engine trying many ways to match before settling on one (or giving up). Most optimisation is really about reducing the number of paths the engine must explore.
- Anchor your patterns. Starting with
^lets the engine fail fast instead of retrying at every position. For validation, wrap the whole pattern in^…$. - Prefer specific classes over the dot.
[^>]+beats.+?because it cannot cross the boundary, so the engine never has to backtrack across it. - Avoid overlapping quantifiers.
\d+\d+or.*.*create an ambiguous split point and waste work — combine them into one. - Make alternation mutually exclusive. In
(a|ab), both branches can match the same text; reorder or restructure so only one can. - Hoist common prefixes.
(abc|abd)is better writtenab(c|d)so the engine commits to the shared prefix once. - Use atomic groups or possessive quantifiers where the engine supports them to prevent needless backtracking.
- Do not reach for regex when a string method will do. A fixed-substring search with
indexOforincludesis faster and clearer than a regex.
The Analyzer tab gives every pattern a readability and maintainability grade and a breakdown of its length, group count, quantifier count and lookaround usage, with concrete suggestions. Measuring on realistic input is the golden rule: a pattern that is instant on your test string can still melt down on a crafted one, which is exactly the risk the next section addresses.
Regex security & ReDoS
ReDoS — Regular Expression Denial of Service — is a real, frequently-exploited vulnerability. It happens when a pattern can match the same text in exponentially many ways, so a malicious, almost-matching input forces the engine to explore an astronomical number of paths before failing. A single request can pin a CPU core for seconds or minutes, blocking a server thread and taking the service down. Because so many validation patterns for emails, URLs and dates contain risky nesting, ReDoS regularly appears in security advisories for popular libraries.
The hallmark of a ReDoS-prone pattern is a nested quantifier — a repetition applied to a group that already contains a repetition:
Dangerous: (a+)+$ on "aaaaaaaaaaaaaaaaaaaaX" → exponential backtracking
Dangerous: (.*)*$ same shape, same explosion
Dangerous: (a|a)+$ overlapping alternation, many redundant paths
Safe: a+$ one way to match — linear timeThe Analyzer tab statically scans your pattern for these shapes — nested quantifiers, quantified overlapping alternation and adjacent open-ended quantifiers — and returns a safety score from 0 to 100 with specific findings and fixes. To harden a pattern: make every part match in exactly one way, replace .* with a specific negated class, anchor with ^ and $, and use atomic groups or possessive quantifiers where available. For input you do not control at all, consider a linear-time engine like RE2 (used by Go and Rust), which cannot backtrack and therefore cannot suffer ReDoS — at the cost of dropping backreferences and lookarounds.
Two more security notes. First, never use regex as your only defence against injection or XSS — validate structurally and encode on output; regex is a filter, not a sandbox. Second, treat any pattern that matches secrets (API keys, card numbers, SSNs) as sensitive itself: the Library tab includes secret-scanning patterns precisely so you can find and redact leaked credentials in logs and commits.
Regex for developers: engines & code generation
The same pattern can behave differently across languages because each ships a different regex engine with its own feature set and performance guarantees. The two broad families are backtracking engines (JavaScript/ECMAScript, PCRE in PHP and Perl, Python, Java, .NET), which are feature-rich but can suffer ReDoS, and finite-automaton engines (RE2 in Go and Rust), which guarantee linear time but drop backreferences and lookarounds.
| Feature | JS | PCRE | Python | Java | .NET | RE2 |
|---|---|---|---|---|---|---|
| Lookahead | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Lookbehind | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Backreferences | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Atomic groups | ✗ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Possessive quantifiers | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ |
| Inline flags (?i) | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Named group spelling | (?<n>) | (?<n>) | (?P<n>) | (?<n>) | (?<n>) | (?P<n>) |
The Code tab turns your current pattern and flags into a ready-to-run snippet for ten languages — JavaScript, TypeScript, Python, PHP, Java, C#, Ruby, Go, Rust and Perl — complete with a test, a match loop and a replace, and with the flags mapped to each language’s API (the JavaScript i flag becomes re.IGNORECASE in Python and Pattern.CASE_INSENSITIVE in Java). It also handles string escaping correctly, which is a frequent source of “works in the tester, fails in code” bugs: a backslash that survives in a Python raw string must be doubled in a Java string literal. The Analyzer tab’s compatibility scan lists exactly which engines would reject or reinterpret your specific pattern before you ship it.
Regex validation examples
Validation is the most common reason developers reach for regex. Below are battle-tested patterns you can load and test from the Library tab. Remember the golden rule: regex checks the shape of input, not its truth — an email pattern confirms the format but only a verification email confirms the address exists.
| What | Pattern | Notes |
|---|---|---|
| Email (pragmatic) | ^[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}$ | Good for forms; full RFC 5322 is far longer |
| URL (http/https) | https?:\/\/[\w.-]+\.[a-z]{2,}\S* | Matches links incl. path and query |
| IPv4 | (?:25[0-5]|2[0-4]\d|1?\d?\d)(\.…){3} | Validates each octet to 0–255 |
| ISO date | \d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) | Shape only — parse for real validity |
| Strong password | (?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).{8,} | Lookaheads stack the requirements |
| UUID v4 | [0-9a-f]{8}-…-4[0-9a-f]{3}-[89ab]… | Note the “4” and variant nibble |
A few validation principles worth internalising. Always anchor validation patterns with ^ and $, or a partial match will let “abc123” pass a “digits only” check. Validate loosely, verify strictly: accept anything plausibly an email, then confirm by sending mail; accept a date’s shape, then parse it with a real date library to reject 30 February. And do not over-engineer: a 500-character “perfect” email regex is harder to maintain and more likely to be ReDoS-prone than a simple one paired with proper verification.
Regex debugging guide
When a pattern misbehaves, work through this checklist — most regex bugs fall into a handful of well-known categories, and this tool surfaces each one:
- Matching too much? It is almost always greedy matching. Make the quantifier lazy (
.+?) or swap the dot for a negated class ([^x]+). Watch it change live in the Tester. - Matching nothing? The Tester shows “no matches” for a valid pattern. Open the Explainer to see what the pattern actually expects — often an unescaped metacharacter or a wrong anchor.
- Works in the tester, fails in code? Usually flags or escaping. Online testers default to the
gandmflags; in code you must set them explicitly and double backslashes in ordinary string literals. The Code tab generates correctly-escaped snippets. - Wrong group captured? Mixing named and numbered groups shifts the numbering. Use the match cards, which list every group with its name and position, and prefer named groups.
- Hangs on certain input? That is catastrophic backtracking. Run the pattern through the Analyzer to find the nested quantifier and rewrite it.
- Behaves differently in another language? Check the compatibility matrix in the Analyzer — named-group syntax, lookbehind length and possessive quantifiers all vary by engine.
The fastest debugging loop is: paste a representative sample into the Tester, watch the highlights update as you adjust the pattern, lean on the Explainer when behaviour surprises you, and finish with the Analyzer before deploying a pattern that will touch untrusted input. Because the whole workflow runs in your browser with no network round-trips, the feedback is instant.
Frequently asked questions
54 answers about regex syntax, capture groups, lookarounds, ReDoS and cross-language compatibility.
A regular expression is a compact, formal language for describing patterns in text. Instead of searching for one fixed string, you describe a shape — “three digits, a dash, then four digits”, or “an email-like token” — and the regex engine finds every piece of text that fits. Regex powers find-and-replace, input validation, log parsing, syntax highlighting and data extraction across virtually every programming language and editor.
Open the Tester tab, type your pattern in the pattern box and your sample text below. Matches highlight live as you type, and every match is listed with its position and capture groups. Toggle the g, i, m, s, u, y and d flags to change matching behaviour, and switch on Replace mode to preview a search-and-replace. Everything runs in your browser, so it is instant and private.
Flags modify how a pattern is applied. g (global) finds every match instead of stopping at the first; i (ignore case) makes matching case-insensitive; m (multiline) makes ^ and $ match at every line break; s (dotall) lets the dot match newlines; u (unicode) enables full code-point handling and \p{…} properties; y (sticky) matches only from the current position; and d (indices) records the start and end offset of every group. This tool exposes all seven as toggles.
A capture group is a part of a pattern wrapped in parentheses, like (\d{4}). When the pattern matches, the text inside each group is stored separately so you can extract or reuse it. Groups are numbered from left to right starting at 1, and the whole match is group 0. The Tester lists every captured group for each match, and the replacement field can reference them with $1, $2 and so on.
A named group uses the syntax (?<name>…) so you can refer to the captured text by a meaningful name rather than a number. For example (?<year>\d{4})-(?<month>\d{2}) captures “year” and “month”. Named groups make patterns self-documenting and make replacement strings ($<year>) and code much easier to read. Note that Python, Go and Rust spell this (?P<name>…).
A greedy quantifier (* + {n,}) matches as much text as possible, then backtracks if needed. A lazy quantifier — the same token followed by a question mark (*? +? {n,}?) — matches as little as possible. The classic example is <.+> versus <.+?> on “<a><b>”: the greedy version matches the whole string, while the lazy version stops at the first “>”. Use lazy quantifiers when you want the shortest match.
A lookahead is a zero-width assertion that checks what comes next without consuming it. A positive lookahead (?=…) succeeds only if the following text matches; a negative lookahead (?!…) succeeds only if it does not. For example \d+(?=px) matches the digits in “16px” but not the “px”, and a password rule like (?=.*\d) asserts “contains a digit somewhere” without fixing its position.
A lookbehind asserts what comes immediately before the current position. A positive lookbehind (?<=…) requires the preceding text to match; a negative lookbehind (?<!…) requires it not to. For instance (?<=\$)\d+ matches the number in “$50” without including the dollar sign. JavaScript supports variable-length lookbehind, but some engines (Java, older PCRE) only allow fixed-length.
Catastrophic backtracking happens when a regex can match the same text in exponentially many ways, so a non-matching input forces the engine to explore an astronomical number of paths before giving up. The usual cause is a nested quantifier such as (a+)+ or (.*)* . On a long, almost-matching string this can freeze a thread for seconds or minutes. The Analyzer tab scans your pattern for these shapes and explains how to fix them.
ReDoS — Regular Expression Denial of Service — is an attack that exploits catastrophic backtracking. An attacker sends a specially crafted input that makes a vulnerable regex run for a very long time, exhausting CPU and blocking the server. Because many validation patterns (for emails, URLs and so on) contain risky nesting, ReDoS is a real production threat. Scan untrusted-facing patterns in the Analyzer and prefer linear-time constructs.
Avoid nested quantifiers like (a+)+ and overlapping alternation like (a|ab)+ . Make the parts of your pattern mutually exclusive so there is only one way to match. Anchor patterns with ^ and $ where possible, prefer specific character classes over .* , and use atomic groups or possessive quantifiers in engines that support them. For fully untrusted input, consider a linear-time engine such as RE2 (used by Go and Rust), which cannot backtrack at all.
A practical pattern is ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ , which checks for a local part, an @, a domain and a 2+ letter top-level domain. It is good enough for forms, but be aware the full RFC 5322 grammar is far more permissive. For high assurance, validate the format loosely and then confirm the address by sending a verification email. The Library tab includes both a pragmatic and a stricter email pattern.
Phone formats vary hugely by country, so a single perfect pattern does not exist. A forgiving international matcher such as \+?\d{1,3}[\s.-]?\(?\d{1,4}\)?(?:[\s.-]?\d{2,4}){2,4} handles country codes, brackets and common separators. For strict validation, normalise the input first (strip spaces and punctuation) and then check the digit count, or use a dedicated library like libphonenumber.
Use the URL pattern in the Library tab: https?:\/\/(?:www\.)?[-\w@:%.+~#=]{1,256}\.[a-z]{2,}\b(?:[-\w()@:%+.~#?&/=]*) . It matches http and https links including path, query and fragment. For parsing rather than just matching, the platform URL API or this site’s URL Encoder / Decoder tool gives you each component reliably without a fragile pattern.
By default the dot matches any single character except a line break. With the s (dotall) flag it also matches newlines, so a.b can span lines. To match a literal dot, escape it as \. — a common mistake is writing a.b when you mean a\.b , which then matches “axb” as well.
\d matches a digit (0–9); \w matches a “word” character, meaning a letter, digit or underscore; and \s matches whitespace such as spaces, tabs and newlines. Their uppercase versions are negations: \D is any non-digit, \W any non-word character and \S any non-whitespace. With the u flag in Unicode mode, these classes can be extended to match characters beyond ASCII.
* means “zero or more” of the preceding token, so it can match nothing at all. + means “one or more”, so at least one occurrence is required. For example, ab* matches “a”, “ab” or “abbb”, while ab+ requires at least one “b” and so will not match a lone “a”. Add ? after either to make them lazy.
^ asserts the start of the string and $ asserts the end. Wrapping a pattern in ^…$ forces it to match the entire input, which is essential for validation — without anchors, ^\d+ would match “abc123” because the digits appear somewhere. With the m (multiline) flag, ^ and $ instead match at the start and end of each line.
Switch on Replace mode in the Tester tab, enter a replacement string and watch the output update live. In the replacement you can reference captured groups: $1, $2 for numbered groups, $<name> for named groups, $& for the whole match, and $$ for a literal dollar sign. For example, replacing (\w+)\s(\w+) with $2 $1 swaps two words.
Enable the g (global) flag and the Tester lists every match with its position. The Extract tab goes further: it offers ready-made patterns for emails, URLs, phone numbers, dates, IP addresses, hashtags and more, and lets you export the extracted values as plain text or CSV. It is ideal for mining structured data out of logs or pasted documents.
An anchor is a zero-width token that matches a position rather than a character. The main anchors are ^ (start), $ (end), \b (word boundary) and \B (not a word boundary). Because they consume no characters, anchors are used to constrain where a match may occur — for example \bcat\b matches the word “cat” but not the “cat” inside “category”.
\b matches the position between a word character (\w) and a non-word character (or the start/end of the string). It lets you match whole words without consuming surrounding characters. \bcat\b matches “cat” as a standalone word but skips “concatenate”. Inside a character class, [\b] means the backspace character instead — a common source of confusion.
Both group sub-patterns so a quantifier or alternation applies to the whole group, but a capturing group (…) also stores its match for later reference, while a non-capturing group (?:…) does not. Use non-capturing groups when you only need grouping for structure — they are slightly faster and keep your group numbers tidy, which matters when you reference groups by number.
A backreference matches the same text a previous group captured. \1 refers to group 1, and \k<name> refers to a named group. They are great for finding repetition: (\w+)\s+\1 finds a doubled word, and (["']).*?\1 matches a quoted string that ends with the same quote character it started with. Note that the linear-time RE2 engines (Go, Rust) do not support backreferences.
Alternation, written with the pipe |, means “match this OR that”. cat|dog matches either word. Alternation has very low precedence, so ^cat|dog$ means “starts with cat” OR “ends with dog”, not “the whole string is cat or dog”. Wrap alternatives in a group to scope them: ^(cat|dog)$ . Order matters in backtracking engines — the engine tries the leftmost branch first.
Use a counted quantifier. {3} means exactly three of the preceding token, {2,4} means between two and four, and {2,} means two or more. For example \d{3}-\d{4} matches a seven-digit phone fragment, and [a-z]{8,} matches a lowercase word of at least eight letters. There is no “up to n with no minimum” shorthand other than {0,n}.
The u flag puts JavaScript regex into Unicode mode. It makes the engine treat the pattern and input as sequences of code points rather than UTF-16 units, so astral characters such as emoji match correctly, and it enables Unicode property escapes like \p{L} (any letter) and code-point escapes like \u{1F600}. Without u, those escapes are interpreted literally. The newer v flag is a stricter superset.
Enable the u flag and use Unicode property escapes. \p{L} matches any letter in any script, \p{N} any number, and \p{Emoji} (or \p{Extended_Pictographic}) matches emoji. To match a specific emoji by code point, write \u{1F600} . Be careful: many emoji are sequences of several code points joined by zero-width joiners, so counting “characters” is subtler than it looks.
This is almost always greedy matching. A quantifier like .+ grabs as much as it can, so <.+> on “<a><b>” swallows everything between the first “<” and the last “>”. Make the quantifier lazy (.+?) to stop at the first valid endpoint, or replace the dot with a more specific class such as [^>]+ so it physically cannot cross the boundary you care about.
There are two different needs. To let ^ and $ match at each line break, use the m (multiline) flag. To let the dot match newline characters so a pattern can span lines, use the s (dotall) flag — or use [\s\S] as a “match anything including newlines” class when an engine lacks the s flag. They are independent and can be combined.
They are different implementations with different feature sets and performance guarantees. ECMAScript (JavaScript) and PCRE (PHP, Perl) are backtracking engines that support lookarounds and backreferences but can suffer ReDoS. RE2 (Go, Rust) is a finite-automaton engine that guarantees linear-time matching but deliberately omits backreferences and lookarounds. The Analyzer tab shows a feature-compatibility matrix across seven engines.
Mostly, but with caveats. Basic patterns are portable, yet named-group syntax, lookarounds, atomic groups, possessive quantifiers and Unicode properties differ between engines. The Analyzer tab scans your pattern and lists exactly which engines would reject or reinterpret it, and the Code tab generates ready-to-run snippets for JavaScript, TypeScript, Python, PHP, Java, C#, Ruby, Go, Rust and Perl.
Open the Code tab, which generates equivalent, runnable code for ten languages from your current pattern and flags. It maps JavaScript flags to each language’s API — for example the i flag becomes re.IGNORECASE in Python and Pattern.CASE_INSENSITIVE in Java — and escapes the pattern string correctly for that language’s string rules. Always re-test in the target engine, since edge-case behaviour can differ.
Common reasons include different default flags, different newline handling for ^ and $ , different named-group syntax, and the presence or absence of features like lookbehind and possessive quantifiers. String escaping also differs: a backslash that survives in a raw Python string may need doubling in a Java string literal. The Code tab handles that escaping for you, and the compatibility matrix highlights behavioural differences.
Precede any metacharacter with a backslash to match it literally. The characters that usually need escaping are . ^ $ * + ? ( ) [ ] { } | \ and / . For example, to match a literal price like “$19.99” you write \$19\.99 . Inside a character class, far fewer characters are special — typically only ^ , ] , - and \ .
The question mark has three jobs depending on context. After a token it means “optional” (zero or one), as in colou?r matching both spellings. After another quantifier it makes it lazy, as in .+? . And immediately after an opening parenthesis it introduces a special group, such as (?:…) non-capturing, (?=…) lookahead or (?<name>…) named group.
Use \s to match any whitespace and \s+ to match runs of it. To collapse multiple spaces into one, replace \s+ with a single space. To trim leading and trailing whitespace per line, match ^\s+|\s+$ with the g and m flags and replace it with nothing. The Library tab includes a ready-made trimming pattern.
Use a lazy quantifier or a negated class. To grab the text inside parentheses, \(([^)]*)\) is robust because [^)]* cannot cross a closing bracket. A lazy alternative is \((.*?)\) , but the negated-class version is usually faster and safer. For quotes, "([^"\\]*(?:\\.[^"\\]*)*)" correctly handles escaped quotes inside the string.
Both are tools to prevent backtracking and avoid ReDoS. An atomic group (?>…) matches its contents and then “locks in” the result, refusing to give characters back. A possessive quantifier (a++, a*+) does the same for a single quantifier. They make patterns faster and safer on untrusted input, but JavaScript supports neither — the Analyzer flags them when present so you know your pattern is not portable to JS.
Use named groups to label what you capture, prefer non-capturing groups where you do not need the value, break very long patterns into documented parts in code, and add comments using the x (extended) flag in engines that support it. The Analyzer tab gives a readability and maintainability grade and points out specific issues such as overusing lookarounds or long alternations.
Not necessarily. For a simple fixed-substring search, indexOf or includes is usually faster and clearer than a regex. Regex shines when the pattern is genuinely variable — multiple delimiters, optional parts, validation rules. A well-written, anchored regex is fast, but a careless one with nested quantifiers can be catastrophically slow. Measure on realistic input rather than assuming.
For IPv4, a correct pattern validates each octet to 0–255: \b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b . A naive \d{1,3}(\.\d{1,3}){3} would wrongly accept “999.1.1.1”. IPv6 is more complex because of the “::” compression rule. Both patterns are in the Library tab ready to load and test.
For an ISO date use ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ , and for 24-hour time ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ . Regex can check the shape and ranges but not true calendar validity such as 30 February, so always parse the result with a real date library afterwards. The Library tab includes ISO date, time and datetime patterns.
For anything but the simplest extraction, no — HTML and JSON are nested, recursive formats that regular expressions cannot fully describe. A regex can grab a tag name or a quoted attribute, but it will break on edge cases like nested tags, comments and CDATA. Use a real parser (the DOM, a JSON parser) for structure, and reserve regex for small, well-bounded extraction tasks.
The d flag tells the engine to record the start and end offset of the whole match and of every capture group, exposing them on the match result’s indices property. It is invaluable for syntax highlighting, building editors and reporting exactly where in the input each group matched. This tool enables it internally so it can show you precise positions for every group.
Use a negative lookahead anchored to the start. For example, ^(?!.*foo)\w+$ matches a word that does not contain “foo” anywhere. The lookahead (?!.*foo) asserts “from here, ‘foo’ does not appear ahead”, and because it is zero-width the rest of the pattern still matches the actual characters. This “tempered” technique is a powerful way to express exclusions.
Usually it is flags or escaping. Online testers often default to the g and m flags, and they show the pattern without the language’s string escaping. In code you must double backslashes inside ordinary string literals (or use a raw/verbatim string), and set the flags explicitly. Paste your pattern into the Code tab to get a snippet with the correct escaping and flag mapping for your language.
Make a token or group optional with ? (zero or one). For example https?:// matches both “http://” and “https://” because the “s” is optional, and (\+\d{1,3}\s)?\d{7,} makes an international dialling prefix optional. Group multiple optional tokens with (?:…)? so the whole block can be present or absent together.
\b matches a word boundary — the edge between a \w character and a non-\w character (or string edge). \B matches the opposite: any position that is not a word boundary, i.e. between two word characters or between two non-word characters. \Bcat\B would match “cat” only when it is embedded inside a longer word, such as in “scatter”.
Enable the g flag and the Tester shows the total match count alongside the highlighted results. Programmatically, in JavaScript you can use [...text.matchAll(re)].length , in Python len(re.findall(pattern, text)) , and so on. Be careful with zero-width patterns: a pattern that can match the empty string needs care to avoid counting an infinite number of positions.
Yes. By default abc matches only lowercase “abc”. Add the i flag to make matching case-insensitive so it also matches “ABC” or “Abc”. If you need case-insensitivity for only part of a pattern, some engines (not JavaScript) support inline modifiers like (?i:abc) , but in JavaScript you typically apply i to the whole regex.
Completely. All compilation, matching, replacement, analysis and code generation run locally in your browser using the native RegExp engine — your patterns and test data are never uploaded, logged or stored on a server. That makes it safe to test patterns against confidential logs, internal data or proprietary text. The tool also works offline once the page has loaded.
Yes, it is completely free with no sign-up, no usage limits and no watermarks. Test, build, explain, analyze and generate code for as many patterns as you like. An optional Pro tier removes ads and adds conveniences like saved pattern collections, but every core feature — including the analyzer, the library and the code generator — is free forever.
The Explainer tab tokenises your pattern from left to right and describes each piece in plain English — anchors, character classes, quantifiers, groups, lookarounds and escapes — with an indented, colour-coded breakdown. It also produces a one-sentence summary of what the whole pattern does. It is the fastest way to understand an unfamiliar regex or to learn how a construct behaves.
Related Tools
Explore More Tools
Go ad-free & unlock power features
- Zero ads, faster focused workflow
- Upload 50MB+ files & batch process
- Priority AI type & schema generation