What this regex tester runs, and where
A regular expression (regex) is a compact way of describing the shape of a piece of text so that you can search for it, validate it, pull parts out of it or rewrite it. Instead of writing "an 'a', then one or more digits, then an at-sign", you write a short pattern and let the engine do the matching. Typical jobs are checking form fields, cleaning log files, bulk-editing text and tidying scraped data.
This page uses the regular expression engine built into your browser, which is the JavaScript (ECMAScript) dialect. A pattern that works here can be pasted straight into new RegExp(...) or a /pattern/flags literal in JavaScript or TypeScript. Other languages have their own dialects (PCRE in PHP, Python's re, Java, .NET and so on) that agree on the basics but differ in details, covered in the dialect section below. Everything runs locally: the page builds a RegExp object from what you type and runs it over the test text in your browser tab. Neither the pattern nor the text is sent anywhere, and nothing is stored. Even so, avoid pasting real personal data into test boxes; sample strings are enough.
Syntax cheat sheet
| Token | Meaning | Example |
|---|---|---|
. | Any single character except a line break (with the s flag, line breaks too) | a.c matches abc, a1c |
\d \w \s | Digit / ASCII letter, digit or underscore / whitespace | \d\d matches 12 |
[abc] [^abc] | One character from the set / one character not in the set | [A-Z] matches a capital letter |
* + ? | Zero or more / one or more / zero or one | ab+ matches ab, abbb |
a{2,3} | Between 2 and 3 repetitions | \d{4} matches exactly four digits |
^ $ | Start / end of the string (of each line with the m flag) | ^abc$ |
\b | Word boundary (between a word character and a non-word character) | \bcat\b |
(β¦) (?:β¦) | Capturing group / non-capturing group | (ab)+ |
a|b | Alternation: a or b | cat|dog |
(?=β¦) (?!β¦) | Lookahead: followed by / not followed by | \d+(?=%) |
(?<=β¦) (?<!β¦) | Lookbehind: preceded by / not preceded by | (?<!\d)\d{5}(?!\d) |
One trap: \w and \b only know ASCII letters, digits and underscore. In /\w+/ the text "naΓ―ve" stops at the Γ―, and Chinese, Japanese or Korean text contains no word characters at all, so \bcat\b even matches inside "catη«". To match letters of any language, use a Unicode property escape with the u flag, for example \p{L}.
Flags
- g (global): find every match instead of stopping at the first. In
replace, without g only the first match is replaced. - i (ignore case): letters match regardless of case.
- m (multiline):
^and$match at the start and end of each line, not just of the whole text. Essential for line-by-line checks. - s (dotAll):
.also matches line breaks, useful for tags that span several lines. - u (unicode): treats the text as code points rather than 16-bit units and enables property escapes such as
\p{L}. Without it an emoji counts as two characters:/^.$/fails on "π" but/^.$/usucceeds. - y (sticky): match only at the position stored in
lastIndex.
Newer engines add d (index ranges for groups) and v (an extended Unicode mode); they work only where your browser supports them. This tool passes whatever flags you type to the browser, so an unsupported or repeated flag shows up as an error message. Without g the tool lists just the first match, mirroring a single exec() call.
Ready-made patterns (each one run and checked in Node.js)
These patterns are in the preset buttons above. For each one, the sample text really does match, or really is rejected, as described.
Email address
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b with the g and i flags matches alex@example.com and a.b+c@mail.co.uk, and skips bad@x (no top-level domain) and @no.com. The full email grammar (RFC 5322) is far richer than this, so no short pattern accepts every valid address or catches every typo. Use it as a first filter and confirm ownership by sending a message.
US-style phone number
(?:\(\d{3}\)\s?|\b\d{3}[-.\s])\d{3}[-.\s]\d{4}\b matches (555) 123-4567, 555-123-4567 and 555.123.4567, while 55-1234-567 and an unseparated 5551234567 are rejected. It checks the shape only. It says nothing about whether the number exists, and other countries use other layouts.
ISO date (YYYY-MM-DD)
\b(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\b limits the month to 01-12 and the day to 01-31 and captures year, month and day. In the sample, 2026-13-01 is rejected but 2026-02-31 passes: a regex sees format, not calendars. Validate real dates with a date library afterwards.
URL, IPv4, hex colour, ZIP code
- URL:
https?:\/\/[^\s<>"']+stops at whitespace, angle brackets or quotes. A trailing full stop or bracket from the surrounding sentence may stick to it, so clean up afterwards. - IPv4: each number is built from alternatives that cover 0 to 255, so
192.168.0.1and10.0.0.255match while256.1.1.1and1.2.3do not. - Hex colour:
#(?:[0-9a-fA-F]{3}){1,2}\baccepts exactly 3 or 6 hex digits after the hash:#fffand#C9A961match,#12345does not. - US ZIP code:
(?<!\d)\d{5}(?:-\d{4})?(?!\d)finds five digits, optionally followed by a dash and four more, that are not attached to other digits. 90210 and 10001-1234 match; 123456 is ignored.
Greedy versus lazy quantifiers
*, + and a{2,3} are greedy: they take as much text as they can and give back only if the rest of the pattern fails. Adding ? makes them lazy, taking as little as possible. On <b>first</b> and <b>second</b>, the greedy <b>.*<\/b> returns one match covering everything from the first opening tag to the last closing tag, whereas the lazy <b>.*?<\/b> returns two separate matches. The last two presets show the difference in the match count (1 versus 2). A sturdier alternative is a negated class such as [^<]*, which says "anything except the character that closes the match" and also runs more predictably.
ReDoS: when a pattern freezes the page
JavaScript's engine uses backtracking: when a path fails it goes back and tries another. If a pattern has repetition nested inside repetition, the number of paths can explode as the input grows, a problem known as ReDoS (regular-expression denial of service). The classic case is ^(a+)+$. Run against a row of the letter a followed by a b, it has to try every way of splitting the a's among the inner and outer plus before it can give up. I measured it in Node.js: 24 a's took about 0.1 s and 26 about 0.4 s, and each extra a roughly doubles the time (exact figures depend on the machine), so 40 would effectively never finish. The equivalent ^a+$ fails instantly. If this page's tab hangs while you experiment, wait for the browser's prompt or close the tab.
- Avoid a repeated group that itself contains a repeat, such as
(a+)+or(.*)*, and avoid repeated alternations whose branches overlap, such as(a|a)+or(a|aa)+. - Cap the length of user input before running a regex on it.
- Prefer specific character classes to
.*. - Never run a pattern supplied by an untrusted user on your own server.
The status line warns when a run takes longer than 100 ms. The tool cannot interrupt a run in progress, so try suspicious patterns on a short test string first.
Groups, named groups and replacement
Parentheses create capture groups, listed per match under the results. A named group such as (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) lets you read values by name, which keeps long patterns maintainable. In the replacement box you may use $1 (group 1), $& (the whole match) and $<name> (a named group). Worked check: load the date pattern, test it on 2026-10-13, and use $3/$2/$1 as the replacement to get 13/10/2026. The named-group preset does the same with $<day>/$<month>/$<year>, giving the same result. A second example: \B(?=(\d{3})+(?!\d)) replaced with a comma turns 1234567 into 1,234,567. A group that did not take part in the match is shown as "(none)".
Pitfalls that catch even experienced users
- Reusing a g-flag regex with test(). A regex with g remembers
lastIndex, so callingtest()repeatedly on the same object alternates between true and false (on "aa" with /a/g it returns true, true, false). Create a fresh regex or reset lastIndex. - Empty matches.
'abc'.match(/x*/g)returns four empty strings, one at every position. The tool lists empty matches but does not highlight them. - Escaping in string literals. Inside a JavaScript string you must double the backslash (
"\\d"). In this tool's pattern box type\das it is. - Anchors without m.
^\w$against "a" followed by a line break and "b" matches neither line unless the m flag is on.
Dialect differences
- JavaScript has no inline flags like
(?i), no possessive quantifiers (a++) and no atomic groups, all of which PCRE supports. - Python spells named groups
(?P<name>β¦); JavaScript uses(?<name>β¦). - Some engines offer
\Aand\zfor the very start and end of the text; JavaScript uses^and$without m. - Lookbehind works in current browsers, but check older environments if you must support them.
When not to use a regex
Nested formats such as HTML, XML or JSON cannot be parsed reliably with a regular expression; use a real parser (the JSON Formatter is the better choice for JSON). Meaning is not a regex job either: whether an email inbox exists, whether a date is on the calendar, whether a phone number is in service. Treat a regex as a format filter and put the semantic checks in separate code.
Frequently Asked Questions
How do I see what each capture group matched?
Put parentheses around the part you want. Each entry in the match list shows the value of every group by number, and named groups appear with their names.
What happens if my pattern is invalid?
The browser reports the syntax error and the status line shows its message. Typical causes are unbalanced parentheses or brackets, an unescaped special character, a quantifier with nothing to repeat, or a bad flag.
Why do I only see one match?
Without the g flag a JavaScript regex stops at the first match. Add g to find all matches and to replace all of them.
Does my text leave my browser?
No. The pattern and the test text are processed by your browser's own regex engine on this page. The tool makes no request with them and stores nothing.
Can a regex fully validate an email address?
No. It can only check the format. Sending a confirmation message is the dependable test; a pattern is a quick filter for obvious typos.
Related tools
- Text Diff Checker - compare the text before and after a replacement
- JSON Formatter and Validator - use a parser, not a regex, for JSON
- Text Case Converter - quick case and naming-style changes
- URL Encoder & Decoder - escape special characters in URLs