This tool runs entirely in your browser. Nothing you paste is uploaded.
How you can check →Universal Regex Tester & Builder
Text & DataFree regex builder and tester: start from an example, try it on sample data, and read any pattern back in plain English — for JavaScript, Python, Java, .NET, Go, PHP, grep and sed.
Pattern
Flags for
Flags change how the whole pattern is matched. Toggle one here or on the pills above — the results update either way.
This pattern in every flavor
Type a valid pattern above to see how it translates into every other flavor.
Your flavor, flags and pattern are saved in this browser's local storage — never test data, and never sent anywhere. Turning this off deletes what's saved.
Build from an example
Can't write regex? Select the part you want to match in the test data pane, then use it as an example.
No example yet — select some text above, in the test data pane, then click "Use selection as example." No sample handy? Use the token chips above the pattern box.
Type or paste a pattern above to see matches here.
Test data
Results
No matches to list.
Type a valid pattern above to see the split segments here.
Type a valid pattern above to see paste-ready snippets here.
Cases that must match, and cases that must not — judged live against the pattern above. Part of the share link.
Must match
Must not match
Type a valid pattern above to see it as a railroad diagram here.
Checks the pattern for the known-dangerous shapes (nested variable quantifiers, and a repeated alternation whose branches can start with the same character), then runs a real, bounded, growing-input test against our own matcher and reports the measured step counts. An empty result here means we didn't find one of those shapes — never that the pattern is safe. This can take a moment; it deliberately runs the pattern against adversarial input.
Steps through one match attempt instruction by instruction — the same engine the Matches tab runs, with every dispatched step recorded. Traces a single attempt starting at the position below, not a full scan of the input.
No network activity while you use this tool Show the numbers
- Requests to any other server
- 0
- Requests since you started typing
- —
- Same-origin requests
- 0
Counted live by your browser's own Performance Timeline — the same data the DevTools Network panel reads. It cannot see what a browser extension does, and it is not meant to replace checking for yourself: here is how, in thirty seconds .
What this regex tester does
This is a free regex tester and builder that runs entirely in your browser — nothing you paste is uploaded, logged or stored. Type a pattern, paste text to test it against, and see every match highlighted immediately, with a match table, a cross-check receipt and a replace preview beneath it.
What makes it different is the claim in the flavor picker. Pick "Go RE2" or "POSIX ERE" and the
tool does not quietly run your pattern through JavaScript's own RegExp with a
different label on the dropdown — it parses and matches your pattern under that engine's actual
rules, built from scratch in src/lib/tools/regex/ rather than borrowed from the
browser.
One tester, every flavor
Eight flavors, each with its own capability table rather than a shared guess:
| Flavor | Ships in |
|---|---|
| ECMAScript (RegExp) | JavaScript, TypeScript, Node.js, browsers |
| PCRE2 | PHP (preg_*), R, Apache/nginx rewrite rules, many C/C++ tools |
| Python 3.11+ (re) | Python 3.11+ |
| Java (java.util.regex) | Java, Kotlin, Scala, Android |
| .NET / PowerShell (Regex) | C#, F#, VB.NET, PowerShell |
| Go RE2 (regexp, Go 1.22+) | Go, ripgrep (default mode), Rust regex (closely related engine) |
| POSIX ERE (grep -E, sed -E, awk) | grep -E, egrep, sed -E / -r, awk |
| POSIX BRE (grep, sed default) | grep (no -E), sed (no -E/-r) |
Regex flags explained — i, g, m, s, x and the rest
Flags sit outside the pattern and change how the whole thing is matched. They are also the most common source of a regex that looks right and quietly returns the wrong answer: a flag left off does not raise an error, it just reports 0 matches for a pattern that is fine. Every flag below has a toggle in the workbench above, and switching flavors re-labels them with that engine's own name for the same idea.
The four you will meet most often are i for case-insensitive
matching, the global flag g for finding every match rather than
stopping at the first, m for multiline anchors, and
s — confusingly named Singleline in .NET and DOTALL in Python
and PCRE2 — for letting a dot match a line break.
| Flag | In plain English | Called, per engine |
|---|---|---|
| i ignore case | Treats capital and small letters as the same, so cat also matches Cat and CAT. | Ignore case · Ignore case (PCRE2_CASELESS) · Ignore case (re.IGNORECASE) · Case insensitive (CASE_INSENSITIVE) · Ignore case (-i) |
| m ^ $ per line | Makes ^ mean the start of any line and $ the end of any line. Without it, they only mean the very start and very end of the whole text. | Multiline · Multiline (PCRE2_MULTILINE) · Multiline (re.MULTILINE) · Multiline (MULTILINE) · Multiline (sed/awk per-line default) · Multiline (sed/grep per-line default) |
| s dot spans lines | Lets a dot match a line break too, so one match can run across several lines. Without it, a dot stops at the end of the line. | Dot matches newline · Dot matches newline (PCRE2_DOTALL) · Dot matches newline (re.DOTALL) · Dotall (DOTALL) · Singleline |
| g every match | Keeps searching after the first hit instead of stopping there. This workbench always lists every match either way, so this flag changes nothing you see here — it changes the code you copy from the Code tab. | Global |
| u unicode | Turns on full support for text beyond plain English — accented letters, other scripts and emoji are handled as whole characters rather than being split in half. | Unicode · Unicode (PCRE2_UTF + UCP, PHP's u modifier) |
| v unicode sets | Everything the unicode flag does, plus set arithmetic inside square brackets: you can add, intersect and subtract groups of characters instead of listing them. | Unicode sets |
| y anchored | Only tries to match at one exact position instead of scanning forward for the next place that fits. Used for tokenising, where a gap means the input is malformed. | Sticky |
| x spaces ignored | Lets you spread a long pattern over several lines with spaces and # notes to yourself, all of which are ignored when matching. A space you actually want to match has to be written as \ or [ ]. | Extended / free-spacing (PCRE2_EXTENDED) · Verbose (re.VERBOSE) · Comments (COMMENTS) · Ignore pattern whitespace |
| U lazy default | Flips every + and * around: they grab as little text as possible instead of as much as possible. Adding ? after one flips that particular quantifier back. | Ungreedy (PCRE2_UNGREEDY) · Ungreedy |
| D $ at very end | Makes $ mean the very end of the text and nothing else — not the spot just before a final line break, which is where it would otherwise also match. | Dollar end only (PCRE2_DOLLAR_ENDONLY) |
| a ascii only | Limits \d, \w, \s and \b to plain English digits, letters and spaces, so digits and letters from other languages stop counting. | ASCII-only (re.ASCII) |
| u unicode case | Makes ignore-case work for accented and non-English letters as well, instead of only A to Z. | Unicode case (UNICODE_CASE) |
| U unicode \d \w | Makes \d, \w, \s and \b cover digits and letters from every language, not just the English ones. Almost nobody turns this on, which is why the same pattern can behave differently here than elsewhere. | Unicode character class (UNICODE_CHARACTER_CLASS) |
| c accents match | Treats characters Unicode considers the same as equal — é typed as one character and é typed as an e plus an accent will both match. | Canonical equivalence (CANON_EQ) |
| e JS-compatible | Restricts the engine to the syntax JavaScript also has, and makes \d, \w and \s cover English digits and letters only. | ECMAScript-compatible |
The one worth reading twice is m. Without it, ^ and $
mean the very start and very end of the whole text, so ^ERROR against a
thirty-line log finds at most one match — on line one. With it, they mean the start and end of
every line, which is almost always what someone pasting a log actually wants.
Why the same regex behaves differently in Java, Python and Go
"Regex" is not one language — it is a family of similar-looking grammars that disagree about basic things. A pattern that is correct in one engine can silently do something else entirely in another, and the differences below are the ones that hit ordinary patterns, not exotica.
| Where it bites | What actually differs |
|---|---|
| $ at the end of input | Matches just before a trailing \n in Python, Java, .NET and PCRE2 — not in JavaScript or Go. "^\d+$" against "42\n" behaves differently depending on where it runs. |
| \d and \w | Unicode-aware by default in Python and .NET; ASCII-only in JavaScript, Java and Go unless you opt in. Arabic-Indic digits match \d in Python but not in Java. |
| Lookbehind | Unbounded in JavaScript, Java and .NET; fixed-width only in Python; absent entirely in Go's RE2. |
| Alternation order | Perl-family engines (JS, PCRE2, Python, Java, .NET) return the first alternative the backtracker finds; grep -E and sed -E return the overall longest match. (a|ab)(c|bcd) against "abcd" gives a different split in each family. |
| Group numbering | .NET numbers unnamed groups first and named groups afterwards — (\d)(?<x>\w)(\d) puts the named group at index 3, not 2. |
Switch the flavor picker above on any pattern that touches one of these and the tool re-validates immediately, naming the exact construct that just became unsupported and why — rather than silently producing a different, plausible-looking answer.
Regex in the terminal — grep, sed, awk, ripgrep and PowerShell
A plain grep or sed uses POSIX Basic Regular Expressions by default,
where (, ), { and } are literal
characters unless escaped with a backslash — the reverse of every other flavor here. Add
-E (or GNU's -r for sed) to get POSIX Extended Regular
Expressions instead, which read the way most people expect. Both POSIX modes return the
overall longest match rather than the first one a backtracker finds, which is
why a|ab against "ab" matches a in a Perl-family engine
and ab under grep -E. ripgrep uses the Rust
regex crate by default — no backreferences, no lookaround — and only falls back to
real PCRE2 semantics with its own -P flag. In PowerShell, a bare $1
inside a double-quoted -replace string is eaten by the shell before the regex
engine ever sees it — use single quotes, or a variable, to keep it literal.
Explain any regex in plain English
Most of the time you are not writing a pattern — you are staring at one somebody else wrote, in a config file or a code review, trying to work out what it does before you dare change it. Paste it into the pattern box and the Explain panel reads it back as a sentence: what each group captures, what each quantifier repeats, which parts are optional and where the anchors bind. It is generated from the same parse tree the matcher runs, so the explanation cannot drift from the behaviour — if the engine disagrees with the English, the English is what changes.
This works in the direction people actually need most often, and it is the reason the tool is useful even if you never write a pattern of your own: what does this regex do is a harder question than does this regex work, and nothing about a wall of punctuation answers it on sight.
Build a regex from an example
If you can show the tool a line you want to match, you do not have to know the syntax at all. Paste a sample — a log line, an order number, a date — highlight the part that matters, and the Build from an example panel proposes a pattern that captures it, with the generalisations spelled out: whether those four digits should be exactly four, whether that hyphen is fixed, whether the case matters. You accept the ones you want.
The token chips beside it do the same job from the other end. Every construct in the cheat
sheet below is a chip you can click into the pattern, spelled correctly for the flavor you have
selected — Python's (?P<name>…) where Python needs it, \( and
\{ where POSIX BRE needs those, rather than one spelling pasted everywhere and
hoped for.
See the pattern as a diagram
The Diagram tab draws the pattern as a railroad diagram — the branching picture of every path through the expression, read left to right. Alternation becomes parallel tracks, a quantifier becomes a visible loop, an optional group becomes a bypass. For a pattern with three nested alternations it is usually faster than reading the source, and it makes one specific class of bug obvious on sight: a group that can match empty, which is the shape that turns into the backtracking problem below.
Copy the pattern as working code
A tested pattern still has to survive the trip into your codebase, and that trip is where
correct patterns go wrong — the wrong escaping for the language's string literal, the wrong
quoting for the shell, $1 eaten by PowerShell before the regex engine ever sees
it. The Code tab writes the whole call for you, escaped for the target you
pick:
- JavaScript / TypeScript (literal)
- JavaScript (new RegExp)
- Python (re)
- Java (Pattern)
- C# (Regex)
- PowerShell
- Go (regexp)
- PHP (preg_match)
- Ruby
- Rust (regex crate)
- Bash ([[ =~ ]])
- grep (BRE)
- grep -E (ERE)
- ripgrep
- sed -E
- awk
- jq
- SQL (PostgreSQL)
- SQL (MySQL)
Nineteen targets, including the ones that are hardest to get right by hand: a
grep command with the pattern single-quoted so the shell leaves it alone, a
jq test() call, a PostgreSQL ~ operator, and a
PowerShell -match that survives the shell's own $ interpolation.
Lock the behaviour in with test cases
Under the pattern box are two lists: must match and must not match. Put your real examples in them — the three address formats that have to pass, the two that have to fail — and every edit to the pattern is checked against all of them instantly. It is the same discipline as a unit test, applied at the point where the pattern is still cheap to change, and it catches the classic regression: a tweak that fixes the case you were looking at and silently breaks one you fixed an hour ago.
The lists travel in the share link, so handing someone a pattern also hands them the cases it is supposed to satisfy.
Common regex patterns, ready to use
The pattern library in the workbench carries 27 patterns for the things people ask for most often. Every one of them is checked by our test suite against real must-match and must-not-match cases in every flavor it claims — a library entry whose cases fail turns the build red rather than becoming your bug. Where a pattern is a pragmatic approximation rather than a guarantee, it says so; that caveat is the most important column here.
| Matches | Pattern | Notes |
|---|---|---|
| Email address e.g. a@b.co |
^[^\s@]+@[^\s@]+\.[^\s@]+$
|
The pragmatic HTML5 email pattern used by <input type="email">. No regex validates an email address correctly — the real grammar (RFC 5322) is far larger than anyone actually types, and this pattern accepts some invalid addresses and rejects some valid ones. The only real validation is sending a confirmation email. |
| URL (http/https) e.g. http://example.com |
^https?:\/\/[^\s\/$.?#].[^\s]*$
|
An http(s) URL with an optional path, query and fragment. Deliberately narrow — it accepts http/https only. Use a real URL parser (the WHATWG URL class) for anything that must be correct, not just plausible. |
| IPv4 address e.g. 0.0.0.0 |
^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$
|
A dotted-quad IPv4 address, each octet 0–255. |
| IPv6 address (full form) e.g. 2001:0db8:0000:0000:0000:ff00:0042:8329 |
^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$
|
A full 8-group IPv6 address, no :: shorthand. Only the fully-written 8-group form. Compressed (::) and mixed IPv4-mapped forms need a purpose-built parser — hand-rolling that in regex is exactly the kind of pattern that hides a bug for years. |
| UUID e.g. 123e4567-e89b-12d3-a456-426614174000 |
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
|
A UUID/GUID in the standard 8-4-4-4-12 hyphenated form, any version. |
| Semantic version e.g. 1.0.0 |
^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?$
|
A semver 2.0.0 version string, with optional pre-release and build metadata. |
| ISO-8601 date/time e.g. 2026-08-22 |
^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?$
|
An ISO-8601 date, or date-time with an optional Z or numeric offset. Checks the shape, not calendar validity — it accepts 2026-02-30. Parse with Date/Temporal to validate that the date actually exists. |
| 24-hour time e.g. 00:00 |
^([01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$
|
An HH:MM or HH:MM:SS time on the 24-hour clock. |
| Hex color e.g. #fff |
^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
|
A CSS hex color, 3, 4, 6 or 8 digits, with the leading #. |
| MAC address e.g. 00:1A:2B:3C:4D:5E |
^([0-9a-fA-F]{2}([:-])){5}[0-9a-fA-F]{2}$
|
A 6-octet MAC address with colon or hyphen separators. |
| JWT (shape only) e.g. eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.dGhpc2lzYXNpZw |
^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$
|
Three base64url segments separated by dots — the JWT shape, not a signature check. This only checks the SHAPE of a JWT. It cannot and does not verify the signature — a syntactically valid JWT can still be forged, expired, or issued for someone else. Verify signatures server-side with a real JWT library. |
| Credit card number (shape only) e.g. 4111111111111111 |
^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{1,7}$
|
13–19 digits, optionally grouped with spaces or hyphens. Checks digit shape only — it does not run the Luhn checksum, and a syntactically valid number here can still be a nonexistent card. Never treat a regex match as proof a card number is real. |
| Phone number (E.164) e.g. +14155552671 |
^\+[1-9]\d{7,14}$
|
An E.164 international phone number: + followed by 8–15 digits. E.164 shape only — it does not know which country codes or lengths are actually assigned. Use a real phone-number library (e.g. libphonenumber) for validation that matters. |
| US ZIP code e.g. 90210 |
^\d{5}(-\d{4})?$
|
A 5-digit US ZIP, optionally with the +4 extension. |
| URL slug e.g. hello-world |
^[a-z0-9]+(?:-[a-z0-9]+)*$
|
Lowercase letters, digits and single hyphens, no leading/trailing hyphen. |
| HTML opening tag (shape only) e.g. <div> |
^<([a-zA-Z][a-zA-Z0-9]*)(\s+[a-zA-Z-]+(=("[^"]*"|'[^']*'))?)*\s*\/?>$
|
A single HTML opening tag with optional attributes. "Don't parse HTML with regex." This matches one well-formed opening tag on its own, nothing more — it cannot handle nested tags, comments, or malformed markup. Use a real HTML parser (DOMParser, an AST-based library) for anything that touches real documents. |
| JavaScript identifier (ASCII) e.g. _private |
^[A-Za-z_$][A-Za-z0-9_$]*$
|
A valid ASCII JavaScript/TypeScript identifier: letter/_/$ then word characters. ASCII-only — real JS identifiers may include Unicode letters, which this pattern deliberately doesn't attempt to enumerate. |
| Log level line e.g. INFO Starting up |
^\s*\[?(TRACE|DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL|CRITICAL)\]?\b
|
Matches a common leading log-level token: TRACE, DEBUG, INFO, WARN(ING), ERROR, FATAL/CRITICAL. |
| Apache/nginx combined log line e.g. 127.0.0.1 - - [22/Aug/2026:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 1043 |
^(\S+) \S+ \S+ \[([^\]]+)\] "([A-Z]+) ([^ "]+) HTTP\/\d\.\d" (\d{3}) (\d+|-)
|
The Apache/nginx "combined" access-log format: IP, timestamp, request line, status, size. |
| Stack-trace frame (Node/V8) e.g. at Object.<anonymous> (/app/index.js:10:5) |
^\s*at (.+?) \(([^:]+):(\d+):(\d+)\)$
|
A single "at fn (file:line:col)" V8 stack-trace frame. |
| key=value pair e.g. PORT=3000 |
^([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|\S*)$
|
A bare or quoted key=value pair, as seen in .env files and log fields. |
| Quoted CSV field e.g. plain |
^(?:[^",\n]*|"(?:[^"]|"")*")$
|
One CSV field: either unquoted with no comma/quote, or a double-quoted field with "" as an escaped quote. |
| Markdown link e.g. [DevToolsCave](https://devtoolscave.com) |
\[([^\]]+)\]\(([^)]+)\)
|
A [text](url) Markdown inline link. |
| Hashtag or @mention e.g. #regex |
[#@]\w+
|
A #hashtag or @mention token: letters, digits and underscores. |
| Duplicated word e.g. the the cat |
\b(\w+)\s+\1\b
|
Catches an accidentally repeated word, like "the the". |
| Trailing whitespace e.g. line with trailing space |
[ \t]+$
|
One or more spaces/tabs at the end of a line. |
| ANSI escape codes e.g. [31mred text[0m |
\x1b\[[0-9;]*m
|
Strips terminal color/formatting escape sequences from captured log output. |
The patterns above are the ECMAScript spelling, which every flavor here can express. Load one from the library in the workbench and it is rewritten for whichever flavor you have selected, or reports plainly that the flavor cannot express it — Go's RE2 has no lookaround, so a pattern that needs one is a compile error there, not a silently different result.
Catastrophic backtracking, and how to see it before production does
A pattern like (a+)+$ looks harmless and can take exponentially longer to fail as
the input grows by a single character — the classic cause of a regex that "hangs" a service.
This tool enforces a hard step budget (five million steps per run) so a pathological pattern
reports "gave up after N steps" instead of freezing your tab, which is also why
matching runs in a background worker rather than on the page itself. The Analyse
tab goes further: it scans the pattern for the known-dangerous shapes, builds a real witness
string, and runs it through our own matcher at growing sizes so you see the actual measured
step counts — never a claim that a pattern is "safe," only what was actually tested. The
Debug tab steps through one match attempt instruction by instruction, so you
can see exactly where a slow pattern starts backtracking.
Which regex flavor should I test against?
Whichever one the pattern will actually run on — the point of this tool is that guessing
shouldn't be necessary. If you're deploying to a Java service, test against Java, not
ECMAScript; if the pattern is going into a sed -E script, test against POSIX ERE,
where the leftmost-longest rule and the terminal quoting both matter.
It's also fair to say when another tool is the better choice. regex101 is the category leader for a reason: a wider flavor list, a step-by-step debugger, a saved-pattern library and a large community of examples. If an account and its own hosting model are fine for what you're testing, it's an excellent tool. This one is built around a narrower, more specific trade: no account, no server component of any kind for the matching itself — every flavor's engine ships as part of the page and runs in your browser, which matters most for production log lines, tokens, or anything you'd rather not paste anywhere else, cross-checked live against your own browser's engine on every run.
Per-flavor guides
Testing one specific engine's own rules in depth? Each flavor has its own guide — the quirks table, a worked example, and the FAQ people actually search for when a pattern behaves differently in production than it did in a generic tester. Every one opens this tool with that flavor already selected.
Regex cheat sheet
Every construct below is also a chip in the workbench above: click it and it goes into the pattern, spelled correctly for the flavor you have selected. The meanings are the same strings the chips' own tooltips carry, so this table cannot describe a construct differently from the thing that inserts it.
Characters and shorthand classes
| Construct | Name | Meaning |
|---|---|---|
| . | Any character | Matches any single character. Example: . matches "a", "9", " ". |
| .* | Any number of characters | Matches any run of characters, including none. Example: a.*z matches "az" and "a-anything-z". |
| .+ | One or more characters | Matches one or more of any character. Example: .+ matches "a" but not an empty string. |
| \d | Digit | Matches a single digit 0-9. Example: \d matches "7" in "a7b". |
| \d* | Any number of digits | Matches a run of digits, including none. Example: \d* matches "" and "007". |
| \d+ | One or more digits | Matches 1, 42, 007 — but not an empty string. |
| \D | Not a digit | Matches anything except 0-9. Example: \D matches "a" but not "7". |
| \w | Word character | Matches a letter, digit or underscore. Example: \w matches "a", "9", "_". |
| \w+ | One or more word chars | Matches a run of letters/digits/underscores. Example: \w+ matches "hello_1". |
| \s | Whitespace | Matches a space, tab or newline. Example: \s matches the space in "a b". |
| \. | Literal dot | Matches an actual . character, not "any character". Example: \. matches the dot in "3.14". |
Repetition — quantifiers, greedy and lazy
| Construct | Name | Meaning |
|---|---|---|
| * | Zero or more | Repeats the previous item 0 or more times. Example: ab* matches "a", "ab", "abbb". |
| + | One or more | Repeats the previous item 1 or more times. Example: ab+ matches "ab", "abbb" but not "a". |
| ? | Optional | Makes the previous item optional. Example: colou?r matches "color" and "colour". |
| {3} | Exactly 3 | Repeats the previous item exactly 3 times. Example: \d{3} matches "123". |
| {2,5} | Between 2 and 5 | Repeats the previous item 2 to 5 times. Example: \d{2,5} matches "12" through "12345". |
| {3,} | 3 or more | Repeats the previous item 3 or more times. Example: \d{3,} matches "123" and longer. |
| *? | As few as possible | Repeats as few times as still allows the whole pattern to match. Example: <.*?> on "<a><b>" matches just "<a>". |
Position — anchors and word boundaries
| Construct | Name | Meaning |
|---|---|---|
| ^ | Start of line | Anchors the match to the start of the line/input. Example: ^abc matches "abc" only at the start. |
| $ | End of line | Anchors the match to the end of the line/input. Example: abc$ matches "abc" only at the end. |
| \b | Word boundary | Matches the edge between a word character and a non-word character. Example: \bcat\b matches "cat" but not "category". |
| \B | Not a word boundary | Matches everywhere \b would NOT. Example: \Bcat matches "cat" inside "concatenate". |
Groups, captures and alternation
| Construct | Name | Meaning |
|---|---|---|
| (…) | Group | Groups part of the pattern together, and captures the matched text. Example: (ab)+ matches "ab", "abab". |
| (?:…) | Non-capturing group | Groups part of the pattern without capturing it. Example: (?:ab)+ matches like (ab)+ but doesn't record a capture. |
| (?<name>…) | Named group | Captures part of the match under a name you can refer to later. Example: (?<year>\d{4}) captures "2024" as "year". |
| (…|) | Either / or | Matches one of several alternatives. Example: (cat|dog) matches "cat" or "dog". |
Character sets and ranges
| Construct | Name | Meaning |
|---|---|---|
| […] | One of these | Matches any single character from the set. Example: [aeiou] matches one vowel. |
| [^…] | None of these | Matches any single character NOT in the set. Example: [^aeiou] matches any non-vowel. |
| [a-z] | Lowercase a-z | Matches one lowercase letter. Example: [a-z] matches "m". |
| [A-Za-z] | Any letter | Matches one upper- or lowercase letter. Example: [A-Za-z] matches "M" or "m". |
| [A-Za-z0-9] | Letter or digit | Matches one letter or digit. Example: [A-Za-z0-9] matches "m" or "7". |
Lookaround — lookahead and lookbehind
| Construct | Name | Meaning |
|---|---|---|
| (?=…) | Followed by | Matches a position only if followed by the given text, without consuming it. Example: \d(?=px) matches the 4 in "4px". |
| (?!…) | Not followed by | Matches a position only if NOT followed by the given text. Example: \d(?!px) matches the 4 in "4kg" but not "4px". |
| (?<=…) | Preceded by | Matches a position only if preceded by the given text, without consuming it. Example: (?<=\$)\d+ matches 40 in "$40". |
| (?<!…) | Not preceded by | Matches a position only if NOT preceded by the given text. Example: (?<!\$)\d+ matches 40 in "40kg" but not "$40". |
Where the flavors disagree
| (?<name>...) | named capture group — JS/.NET/Java/PCRE2/Go 1.22+; Python uses (?P<name>...) instead |
| (?<=...) (?<!...) | lookbehind — unbounded in JS/Java/.NET, fixed-width only in Python, absent from Go |
| a++ (?>...) | possessive quantifier / atomic group — Java and PCRE2 have both; .NET has only the atomic group; JavaScript has neither |
| \1 \k<name> | backreference — absent from Go's RE2 entirely |
| \d \w \s | digit / word character / whitespace — Unicode-aware by default in Python and .NET, ASCII-only in JavaScript, Java and Go |
Privacy
Nothing you paste ever leaves your device. Parsing, validation and matching are computed by JavaScript running in your browser, in a background worker so a slow pattern never freezes the page. There is no server to send it to.
Frequently asked questions
- Is this regex tester free?
- Yes — no account, no signup, no limits beyond the caps stated in the tool (1,000 lines / 1 MB of test data per run), and no upload.
- Does my pattern or test data leave my browser?
- No. The matching engine ships as part of this page and runs on your machine. There is no server for it to send anything to.
- Which regex flavors are supported?
- Eight: ECMAScript, PCRE2, Python 3 re, Java, .NET/PowerShell, Go RE2, POSIX ERE and POSIX BRE — each with its own parser and matching rules, not one engine wearing eight labels.
- Why does my regex match here but not in Java?
- The three usual causes are anchors (whether $ matches before a trailing newline), Unicode (whether \d and \w include non-ASCII characters), and lookbehind width (Go has none at all, Python needs a fixed width). Switch the flavor picker to Java and this tool re-validates immediately and names the exact construct that changed.
- Can I test grep or sed patterns?
- Yes — POSIX BRE and ERE are real flavors here, including the leftmost-longest matching rule that grep and sed actually use, which is different from every Perl-family engine's leftmost-first rule.
- How large a test input can I paste?
- 1,000 lines or 1 MB, whichever comes first, stated plainly in the tool when it fires. The reason is that matching runs on your machine, and a runaway pattern against an unbounded paste would freeze your tab rather than fail safely.
- How do you know your results are right?
- Every ordinary pattern is cross-checked against your own browser's built-in RegExp at the moment you run it, and the receipt says so. Where a pattern uses a construct JavaScript can't express (POSIX longest-match, a possessive quantifier, \A), we say plainly that it isn't cross-checkable rather than pretending it is.
- What is catastrophic backtracking?
- A pattern shape — typically a nested or ambiguous quantifier like (a+)+ — that makes some engines take exponentially longer as the input grows by one character. This tool enforces a hard step budget so a pathological pattern reports "gave up after N steps" instead of freezing your tab; a full backtracking analyzer with a witness string is planned for a later update.
- Can this explain a regex somebody else wrote?
- Yes — that is the direction most people need. Paste any pattern and the Explain panel reads it back as plain English: what each group captures, what each quantifier repeats, which parts are optional and where the anchors bind. It is generated from the same parse tree the matcher runs, so the explanation cannot drift from the actual behaviour.
- Can I build a regex without knowing regex syntax?
- Yes. Paste an example of the text you want to match, highlight the part that matters, and the Build from an example panel proposes a pattern with each generalisation spelled out in words — whether four digits means exactly four, whether a hyphen is fixed, whether case matters. The token chips do the same job construct by construct, always in the correct spelling for the flavor you have selected.
- What regex flags does i, g, m and s mean?
- i ignores case, so cat also matches Cat. g keeps searching after the first hit instead of stopping. m makes ^ and $ mean the start and end of every line rather than of the whole text — the one that most often explains a pattern that finds only one match in a long log. s lets a dot match a line break too. Each flavor names them differently (Python's re.MULTILINE, PCRE2_DOTALL) and the tool relabels the toggles when you switch flavors.
- Can I get the pattern as code for my language?
- Yes — the Code tab writes the whole call for nineteen targets, escaped and quoted correctly for each: JavaScript, TypeScript, Python, Java, C#, PowerShell, Go, PHP, Ruby, Rust, Bash, grep, ripgrep, sed, awk, jq, and both PostgreSQL and MySQL. That covers the failures that happen after a pattern is already correct, like a shell eating the quoting or PowerShell consuming $1 before the regex engine sees it.
- Does it show a regex diagram?
- Yes. The Diagram tab draws the pattern as a railroad diagram — alternation as parallel tracks, quantifiers as visible loops, optional groups as bypasses. For a pattern with nested alternation it is usually faster to read than the source, and it makes a group that can match empty obvious on sight, which is the shape behind most catastrophic backtracking.
Explore more tools
Last updated .