Test and debug regex online with live match highlighting, capture-group details, plain-English explanations, and 90+ ready patterns. Free, in your browser.
This regex tester runs your pattern against your test string as you type and shows you exactly what matched, where it matched, and what each capture group caught. Type a pattern in the top box, paste sample text underneath, and every match is highlighted in place while a details panel lists the character offsets and group contents. Nothing is uploaded — the matching happens in your browser using the JavaScript regular expression engine, so your log lines, customer records, and config snippets never leave your machine.
It is built for the two situations where people actually reach for a regex tester: writing a new pattern from scratch and needing fast feedback, and debugging someone else’s pattern that almost works. For the first case there is a library of roughly ninety ready-made patterns across eighteen categories — email, URL, phone, date, IP, payment, password, HTML, colour, files, path, crypto, security, social, markdown, numbers, text, and code — that you can load with one click and then edit. For the second, a live explanation panel breaks the pattern into plain-English components so you can see what a wall of brackets and backslashes is actually asking for.
$1, $2, and so on with their own positions. This is the panel that tells you whether your groups are capturing what you think they are.g global, i case-insensitive, m multiline, s dotAll, u unicode, and y sticky. The flag row next to the pattern box lights up to show which are active.m if you want ^ and $ to anchor to each line, and s if you need . to cross newlines..*.A character class defines a set of characters that a single position may match. [a-z] matches one lowercase letter; [^0-9] matches one character that is not a digit; [A-Fa-f0-9] matches one hex digit. The shorthand classes are \d (digit), \w (word character: letters, digits, underscore), and \s (whitespace), each with an inverted uppercase form — \D, \W, \S. Inside square brackets most metacharacters lose their special meaning, which is why [.+*] matches a literal dot, plus, or asterisk with no escaping. The exceptions are ^ at the start (negation), - between characters (range), and ] and \ themselves.
Quantifiers say how many times the preceding element may repeat: * is zero or more, + is one or more, ? is zero or one, and {3}, {3,}, {3,5} give exact, minimum, and bounded counts. The single most common bug in hand-written regex is applying a quantifier to the wrong element. \d{3}-\d{4} matches three digits, a hyphen, then four digits. (\d-){3} matches “digit hyphen” three times — a very different thing. Group first, then quantify.
By default quantifiers are greedy: they consume as much as possible and then give characters back only if the rest of the pattern fails. Adding ? after a quantifier makes it lazy, consuming as little as possible and expanding only when forced.
Test string: <b>bold</b> and <i>italic</i>
<.+> produces one match: the entire string from the first < to the last >. The greedy .+ ran to the end of the line and only backtracked far enough to find a final >.<.+?> produces four matches: <b>, </b>, <i>, </i>. The lazy quantifier stops at the first > it can.<[^>]+> also produces four matches and is the version to prefer — a negated character class cannot overshoot, so there is no backtracking to undo.That last point matters beyond tidiness. Nested greedy quantifiers over overlapping character sets — the classic shape being (a+)+$ or (\s*\w+)*$ — can make the engine explore an exponential number of paths on input that nearly matches. That is catastrophic backtracking, and when the pattern is applied to user-supplied input it becomes a denial-of-service bug (ReDoS). Paste a long non-matching string into the test box and watch for the page stalling; if a pattern takes noticeably long on a few hundred characters, rewrite it with negated classes and possessive-style anchoring rather than shipping it.
Parentheses do two jobs at once: they group elements so a quantifier or alternation applies to the whole unit, and they capture the matched text for later use. When you only want the grouping, use (?:…). It keeps the numbering of your real groups stable and avoids storing text you will never read.
Worked example on the test string 2026-08-12:
(\d{4})-(\d{2})-(\d{2}) — one match, three groups: $1 = 2026, $2 = 08, $3 = 12.(?:\d{4})-(\d{2})-(\d{2}) — same match, but now $1 = 08 and $2 = 12; the year is grouped but not captured.(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) — named groups, readable in replacement strings as $<year> and far easier to maintain than positional numbers when the pattern grows.A backreference matches whatever a previous group actually captured, not the pattern that captured it. (["'])(.*?)\1 matches a quoted string and guarantees the closing quote is the same character as the opening one — something no character class can express. Similarly \b(\w+)\s+\1\b finds doubled words like “the the” in prose.
Lookaround assertions test whether something is present at a position without consuming any characters, so the text they inspect never appears in the match. There are four forms: positive lookahead (?=…), negative lookahead (?!…), positive lookbehind (?<=…), and negative lookbehind (?<!…).
The everyday use is a password rule that has to check several independent conditions on the same string. ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{12,}$ reads as: from the start, assert somewhere ahead there is a lowercase letter, and separately an uppercase letter, and separately a digit, and separately a symbol — then actually consume at least twelve characters to the end. Each lookahead starts over from position zero, which is why order does not matter and why you cannot express this with a single linear pattern.
Lookbehind is how you match a value while excluding its label: (?<=Authorization:\s)\S+ captures the token without the header name, so the match itself is clean enough to feed straight into a script. Negative lookahead is how you exclude exceptions: ^(?!.*(?:test|staging)\.)[\w.-]+\.example\.com$ matches your production hostnames but not the test ones.
This tester runs the JavaScript engine — the same engine your browser and Node.js use — so what you see here is exactly what String.prototype.match and RegExp.exec will do. Most patterns transfer to other languages unchanged, but a handful of differences bite regularly:
(?<name>…). Python accepts (?P<name>…) as well as the modern form, and older Python code you inherit will use the ?P spelling.re module requires fixed-width lookbehind, so (?<=\s+) is a compile error there — you need the third-party regex module or a restructured pattern.s flag; Python uses re.DOTALL; PCRE uses (?s) inline. Same behaviour, three spellings.$ also matches just before a trailing newline, and \Z is the strict end-of-string anchor. JavaScript has no \Z.u flag before \p{L} and friends work; in Python 3 \w is Unicode-aware by default; in PCRE you generally need the UTF and UCP options.(?>…) and a++ exist in PCRE and Java and are the cleanest defence against catastrophic backtracking. JavaScript has neither, so in JS you prevent backtracking by writing narrower character classes instead.regexp package uses RE2, which has linear-time guarantees but deliberately omits backreferences and lookaround entirely. A pattern that relies on (?=…) will not compile there, no matter how correct it is.The practical rule: prototype here, then check the two or three constructs above against your target language before shipping.
It is free with no signup, and nothing is uploaded. Pattern matching runs entirely in your browser, so you can safely paste production log lines or records that you would not want to send to a third-party server.
The JavaScript engine built into your browser, with all six standard flags available. Patterns using only common constructs behave identically in PCRE and Python; see the flavour section above for the specific cases that differ.
Almost certainly a greedy quantifier. Replace .* with a lazy .*? or, better, with a negated character class such as [^,]* or [^>]* that physically cannot cross the delimiter.
(abc) and (?:abc)?Both group the enclosed elements so quantifiers and alternation apply to the whole unit. Only the first captures the matched text into a numbered group. Use the non-capturing form when you are grouping for structure, so your group numbers stay meaningful.
Python’s standard re module only allows fixed-width lookbehind. A lookbehind containing +, *, or an alternation of different lengths compiles fine in JavaScript and PCRE2 but raises an error in Python. Either fix the width or use the regex package.
m flag actually change?With multiline off, ^ and $ anchor to the start and end of the whole string. With it on, they anchor to the start and end of every line. It has no effect on . — that is the s flag.
That is catastrophic backtracking, and it is a finding rather than a bug. Nested quantifiers over overlapping sets, such as (\w+\s?)+$, force the engine down exponentially many paths on near-matching input. If it stalls here it will stall in production too — rewrite it before shipping.
Wrap it in word boundaries: \bcat\b matches “cat” but not “concatenate”. A word boundary is a zero-width position between a \w and a non-\w character, so it consumes nothing and does not appear in the match.
Only roughly. The library’s simple and RFC 5322 email patterns catch typos and malformed input, which is the honest limit of syntax checking — a syntactically perfect address may still have no mail server behind it. To check whether a domain can actually receive mail, use the Email Validator & MX Checker.
Use the share button. The pattern, test string, and active flags are encoded into the URL, so the link reproduces exactly the state you were looking at.
Once a pattern is producing the right matches, the next step is usually the data itself. Use the JSON Validator & Formatter to check structured output, the YAML to JSON Converter when the extracted values are headed into a config file, and the Dockerfile Generator when the script that runs your pattern needs somewhere to live.
A regular expression (regex) tester allows you to write, test, and debug regex patterns against sample text in real time. Regular expressions are a powerful pattern-matching language used across virtually all programming languages, text editors, command-line tools, and databases. They match strings based on patterns rather than literal values—enabling search, validation, extraction, and replacement operations that would be impractical with simple string methods.
Despite their power, regular expressions have a notoriously steep learning curve. A single misplaced quantifier or forgotten escape character can cause a pattern to match nothing, match too much, or run catastrophically slowly. A regex tester provides instant visual feedback—highlighting matches, showing capture groups, and explaining pattern behavior—transforming regex development from trial-and-error into an interactive process.
Regular expressions define patterns using a combination of literal characters and metacharacters:
| Metacharacter | Meaning | Example | Matches |
|---|---|---|---|
| . | Any character (except newline) | a.c | abc, a1c, a-c |
| * | Zero or more of preceding | ab*c | ac, abc, abbc |
| + | One or more of preceding | ab+c | abc, abbc (not ac) |
| ? | Zero or one of preceding | colou?r | color, colour |
| \d | Any digit [0-9] | \d{3} | 123, 456 |
| \w | Word character [a-zA-Z0-9_] | \w+ | hello, var_1 |
| \s | Whitespace | \s+ | spaces, tabs, newlines |
| ^ | Start of string/line | ^Hello | Hello at line start |
| $ | End of string/line | world$ | world at line end |
| [abc] | Character class | [aeiou] | Any vowel |
| (group) | Capture group | (\d{4}) | Captures 4 digits |
| (?:group) | Non-capturing group | (?:https?):// | Matches but doesn't capture |
| | | Alternation (OR) | cat|dog | cat or dog |
Common regex patterns:
| Use Case | Pattern | Matches |
|---|---|---|
| Email (basic) | [\w.+-]+@[\w-]+.[\w.]+ | user@example.com |
| IPv4 address | \d{1,3}(.\d{1,3}){3} | 192.168.1.1 |
| Date (ISO) | \d{4}-\d{2}-\d{2} | 2024-01-15 |
| URL | https?://\S+ | https://example.com/path |
| Phone (US) | (?\d{3})?[-.\s]?\d{3}[-.\s]?\d{4} | (512) 555-0100 |
.*? instead of .* prevents over-matching in patterns with multiple delimiters^ and $ to ensure the entire string matches, not just a substring(a+)+ can cause exponential processing time; use atomic groups or possessive quantifiersx) to add whitespace and comments to long regex patternsRegular expression (regex) is a pattern-matching language for searching and manipulating text. Uses special characters like . (any character), * (zero or more), + (one or more), ? (optional), [] (character class), () (group). Common uses: validate email/phone formats, extract data from logs, find/replace in code editors, parse URLs, sanitize user input, search documents, split strings. Example: /\d{3}-\d{2}-\d{4}/ matches SSN format 123-45-6789. More powerful than simple string search but harder to read. Use for complex patterns; use indexOf() for simple exact matches. This tool tests patterns with live highlighting.
Email: /^[a-zA-Z0-9.%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/. URL: /https?://(www.)?[-a-zA-Z0-9@:%.+~#=]{1,256}.[a-zA-Z0-9()]{1,6}\b/. Phone (US): /^(?\d{3})?[-.\s]?\d{3}[-.\s]?\d{4}$/. Date (YYYY-MM-DD): /^\d{4}-\d{2}-\d{2}$/. IP address: /^(\d{1,3}.){3}\d{1,3}$/. Hex color: /^#?([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/. Username (alphanumeric): /^[a-zA-Z0-9_]{3,16}$/. Password (min 8, 1 upper, 1 lower, 1 digit): /^(?=.[a-z])(?=.[A-Z])(?=.*\d).{8,}$/. This tool includes common patterns library for quick testing.
Flags modify regex behavior, added after closing delimiter (/pattern/flags). Common flags: g (global) - find all matches, not just first. i (ignore case) - case-insensitive matching (A = a). m (multiline) - ^ and $ match line breaks, not just string start/end. s (dotall) - . matches newlines. u (unicode) - proper unicode character handling. y (sticky) - match at exact position. Example: /test/gi finds all "test", "TEST", "Test" occurrences. Without g, stops after first match. Use g for find-all, i for case-insensitive, m for multi-line text. This tool supports all major flags with real-time preview.
Parentheses () create capture groups to extract matched portions. Example: /(\d{3})-(\d{3})-(\d{4})/ in "555-123-4567" captures "555", "123", "4567" as groups 1, 2, 3. Backreferences reuse captured groups: \1, \2 refer to first, second group. Example: /(\w+)\s\1/ matches repeated words ("the the"). Named groups: /(?\d{3})-(?
Quantifiers (* + {n,m}) are greedy by default - match as much as possible. Example: /<.>/ on "text" matches entire string (greedy). Lazy (non-greedy) quantifiers add ? after quantifier - match as little as possible. Example: /<.?>/ matches "", then "" separately. Greedy: .* (zero or more, greedy), .+ (one or more, greedy), .{2,5} (2-5, greedy). Lazy: .*? .+? .{2,5}?. Use lazy for: HTML tag extraction, avoiding over-matching, parsing nested structures. Use greedy for: full line matching, whole word extraction. This tool shows greedy vs lazy behavior with match highlighting.
Basic email regex: /^[^\s@]+@[^\s@]+.[^\s@]+$/ (allows most valid emails). Comprehensive: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/ (stricter). Validation challenges: RFC 5322 spec is complex (allows quoted strings, comments), international domains (unicode characters), new TLDs (.museum, .technology), plus addressing (user+tag@domain.com). Best practice: use simple regex for UI validation, send confirmation email for real verification. Don't over-restrict (user@domain.co is valid). This tool tests email patterns against real examples and highlights match groups for debugging custom patterns.
Assertions match position, not characters. Positive lookahead (?=pattern) - matches if followed by pattern. Example: /\d(?= dollars)/ matches "5" in "5 dollars" but not "5 euros". Negative lookahead (?!pattern) - matches if NOT followed by pattern. Positive lookbehind (?<=pattern) - matches if preceded by pattern. Example: /(?<=$)\d+/ matches "100" in "$100". Negative lookbehind (?<!pattern). Use cases: password validation (must contain uppercase: (?=.*[A-Z])), extract values after labels, match words except in quotes. Browser support: lookbehind added in ES2018. This tool tests all assertion types with position highlighting.
Common issues: escaping special characters (. * + ? [ ] ( ) { } ^ $ | ) - use backslash . Forgetting anchors - /test/ matches "testing" (use ^test$ for exact match). Wrong flags - case sensitivity (add i flag). Greedy vs lazy - .* vs .*?. Character class mistakes - [a-Z] is wrong (use [a-zA-Z]). Debugging steps: start simple, add complexity incrementally. Test with online tool (this tool!). Use verbose mode if available. Check documentation for your regex flavor (JavaScript vs Python vs PCRE differ). Test edge cases. Use visualization tools. This tool provides live highlighting, match explanation, and error messages for syntax issues.