Regex Tester
Online regex tester that highlights matches in real time. See capture groups, match details, and use common pattern presets.
This regex tester highlights matches in real time as you type your pattern and test string. It shows capture groups, match positions, and detailed match information using JavaScript's native RegExp engine. Paste your pattern and test data, toggle flags, and see exactly what matches - all in your browser with nothing sent to a server.
About Regex Tester
How Regular Expressions Work
A regular expression (regex) is a sequence of characters that defines a search pattern. The regex engine reads the pattern left to right and tries to match it against the input string. When a match is found, the engine records the matched text and its position, then continues scanning for more matches if the global flag is set.
The pattern language uses special characters called metacharacters to describe flexible matches. A dot (.) matches any single character, a backslash-d (\d) matches any digit, and square brackets define a character class like [a-z] for lowercase letters. Quantifiers like * (zero or more), + (one or more), and {n,m} (between n and m) control how many times a preceding element can repeat.
JavaScript Regex Flags
| Flag | Name | What It Does | Example Effect |
|---|---|---|---|
| g | Global | Find all matches, not just the first | /a/g on "banana" finds 3 matches |
| i | Case-insensitive | Ignores upper/lowercase distinction | /hello/i matches "Hello" and "HELLO" |
| m | Multiline | ^ and $ match line starts/ends, not just string start/end | /^foo/m matches "foo" at the start of any line |
| s | DotAll | Dot (.) matches newline characters too | /a.b/s matches "a\nb" |
| u | Unicode | Enables full Unicode matching and \u{} escapes | Correctly handles emoji and surrogate pairs |
The most common combination is gi (global + case-insensitive) for finding all occurrences regardless of casing.
Understanding Capture Groups
Parentheses in a regex pattern create capture groups that extract specific portions of a match. This is one of the most powerful features for data extraction and transformation.
| Pattern | Input | Full Match | Group 1 | Group 2 |
|---|---|---|---|---|
| (\d{3})-(\d{4}) | 555-1234 | 555-1234 | 555 | 1234 |
| (\w+)@(\w+\.\w+) | user@site.com | user@site.com | user | site.com |
| (\d{4})-(\d{2})-(\d{2}) | 2026-04-06 | 2026-04-06 | 2026 | 04 |
| (Mr|Ms|Dr)\. (\w+) | Dr. Smith | Dr. Smith | Dr | Smith |
Named groups use the syntax (?<name>...) and make the code more readable. For example, (?<year>\d{4})-(?<month>\d{2}) lets you reference matches by name rather than index number.
Non-capturing groups (?:...) group elements without creating a capture. Use these when you need grouping for alternation or quantifiers but do not need to extract the matched text.
Common Regex Patterns
| Use Case | Pattern | Notes |
|---|---|---|
| Email (basic) | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} | Simplified - RFC 5322 full spec is much longer |
| URL | https?://[^\s/$.?#].[^\s]* | Matches http and https URLs |
| IPv4 address | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b | Does not validate range (0-255) |
| Date (YYYY-MM-DD) | \d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]) | Validates month 01-12 and day 01-31 |
| Phone (US) | \(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4} | Matches (555) 123-4567, 555.123.4567, etc. |
| Hex colour | #(?:[0-9a-fA-F]{3}){1,2}\b | Matches #fff and #ffffff |
| HTML tag | <([a-zA-Z][a-zA-Z0-9]*)\b[^>]*> | Opening tags only - use a parser for real HTML |
| Whitespace trim | ^\s+|\s+$ | Leading and trailing whitespace |
These are starting points. Production validation for emails, URLs, and phone numbers usually needs more thorough patterns or dedicated libraries.
Lookahead and Lookbehind
Lookarounds assert that something exists (or does not exist) before or after your match, without including it in the match result. They are zero-width assertions - they check a condition but consume no characters.
| Type | Syntax | Example | Matches |
|---|---|---|---|
| Positive lookahead | X(?=Y) | \d+(?= dollars) | "100" in "100 dollars" |
| Negative lookahead | X(?!Y) | \d+(?! dollars) | "100" in "100 euros" |
| Positive lookbehind | (?<=Y)X | (?<=\$)\d+ | "50" in "$50" |
| Negative lookbehind | (?<!Y)X | (?<!\$)\d+ | "50" in "50 items" but not "$50" |
Lookbehind support was added to JavaScript in ES2018 and works in all modern browsers. Older browsers like IE11 do not support it.
Greedy vs Lazy Quantifiers
By default, quantifiers are greedy - they match as much text as possible. Adding a ? makes them lazy, matching as little as possible. This distinction matters most when parsing structured text.
| Greedy | Lazy | Input | Greedy Result | Lazy Result |
|---|---|---|---|---|
| .+ | .+? | <b>one</b><b>two</b> | <b>one</b><b>two</b> | <b>one</b> |
| \d+ | \d+? | 12345 | 12345 | 1 |
| \w{2,5} | \w{2,5}? | hello | hello | he |
A common mistake is using .* to match content between delimiters. The pattern <.*> applied to "<a>text</b>" matches the entire string because .* is greedy. Use <.*?> or <[^>]*> to match individual tags.
Common Regex Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Unescaped dot | . matches any character, not just a period | Use \. to match a literal dot |
| Missing anchors | /\d{5}/ matches "123456" (partial) | Use /^\d{5}$/ to match exactly 5 digits |
| Greedy HTML parsing | <.*> matches too much | Use <[^>]*> or <.*?> |
| Forgetting global flag | Only first match returned | Add the g flag for all matches |
| Backslash in strings | "\d" in JS becomes just "d" | Use "\\d" or a regex literal /\d/ |
| Using regex for HTML | Regex cannot handle nested structures | Use a DOM parser for real HTML processing |
Regex Engine Differences Across Languages
| Feature | JavaScript | Python (re) | PCRE (PHP) | .NET |
|---|---|---|---|---|
| Lookbehind | Fixed and variable width (ES2018+) | Fixed width only | Fixed width only | Variable width |
| Named groups | (?<name>) | (?P<name>) | (?P<name>) or (?<name>) | (?<name>) |
| Atomic groups | No | No (use re2 module) | Yes (?>...) | Yes (?>...) |
| Possessive quantifiers | No | No | Yes (++, *+) | No |
| Unicode categories | \p{L} with u flag | \p{L} (Python 3) | \p{L} | \p{L} |
| Recursion | No | No | Yes (?R) | Yes (?<name>) |
This tool uses JavaScript's regex engine. Most basic patterns work identically across all languages, but advanced features like atomic groups and recursion are only available in PCRE and .NET.
Catastrophic Backtracking: When Regex Kills Performance
Some regex patterns look innocent but can take minutes or hours to evaluate on certain inputs. This is called catastrophic backtracking, and it happens when the engine has too many ways to match a string and has to try all of them before concluding there is no match.
Classic example: the pattern (a+)+$ applied to the string "aaaaaaaaaaaaaaaaX". The engine tries to match one or more a's (the inner a+), repeated one or more times (the outer +), followed by end of string. Since the X prevents a full match, the engine backtracks through every possible way to divide the a's between the inner and outer groups. For 16 a's, that is 2^15 (32,768) combinations. For 30 a's, it is over a billion. Your browser tab freezes.
Patterns vulnerable to catastrophic backtracking typically have nested quantifiers: (a+)+, (a*)*, (a|b)+ where alternation overlaps, or (.*a){n}. The fix is to restructure the pattern to remove ambiguity. Replace (a+)+ with a+. Replace (a|aa)+ with a+. If the pattern genuinely needs nesting, use atomic groups (?>a+)+ in engines that support them (PCRE, .NET) to prevent backtracking into already-matched groups.
In production code, always set a timeout on regex execution. In JavaScript, Web Workers with a setTimeout kill switch are the standard approach. In Python, the regex module supports a timeout parameter. In server-side code, an unbounded regex on user-supplied input is a denial-of-service vulnerability (ReDoS).
Regex Performance Tips for Production Code
- Anchor when possible.
^patternandpattern$prevent the engine from trying every position in the string. An unanchored pattern on a 100,000-character string tries to match starting from every character. - Use character classes over alternation.
[abc]is faster thana|b|cbecause the engine checks a single lookup table instead of trying each alternative. - Be specific with quantifiers.
\d{4}is faster than\d+when you know the length.[^"]*is much faster than.*?for matching content between delimiters. - Compile once, use many times. In JavaScript, create the RegExp object outside the loop. In Python, use
re.compile(). Recompiling the pattern on every iteration adds overhead. - Avoid .* at the start of a pattern. Starting with
.*fooforces the engine to scan to the end of the string and then backtrack. Starting withfoo(maybe with the m flag) is orders of magnitude faster on long inputs.
Unicode Regex Patterns
Modern applications handle text in dozens of languages. The traditional [a-zA-Z] only matches ASCII letters, missing accented characters, Cyrillic, Chinese, Arabic, and everything else. Unicode-aware regex solves this with property escapes:
| Pattern | Matches | Example Matches |
|---|---|---|
| \p{L} | Any Unicode letter | a, Z, e, n, C, alpha |
| \p{N} | Any Unicode number | 0-9, roman numerals, circled numbers |
| \p{Emoji} | Emoji characters | heart, thumbs up, fire (JS with u flag) |
| \p{Script=Greek} | Greek script characters | alpha, beta, gamma, omega |
| \p{Script=Han} | CJK ideographs | Chinese/Japanese Kanji |
In JavaScript, you must enable the u flag to use \p{...} escapes. Without it, \p is just a literal "p". Python 3's re module supports \p{L} natively. PCRE and .NET have supported it for years. If you build an app that validates names, addresses, or any user-generated content, use \p{L} instead of [a-zA-Z] to avoid rejecting perfectly valid international text.
Named Capture Groups in Practice
Named capture groups make complex patterns far more readable and maintainable. Instead of referring to groups by index (group 1, group 2), you give them descriptive names:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
In JavaScript (ES2018+), access named groups via match.groups.year, match.groups.month, match.groups.day. In Python, use match.group('year'). In search-and-replace, reference them as $<year> in JavaScript or \g<year> in Python.
Named groups are especially useful in log parsing. A pattern like (?<ip>\d+\.\d+\.\d+\.\d+) - - \[(?<date>[^\]]+)\] "(?<method>\w+) (?<path>[^ ]+) is immediately understandable, while the same pattern with numbered groups requires counting parentheses to figure out which group is which.
Regex Across Common Tools
| Tool | Engine | Syntax Notes |
|---|---|---|
| VS Code (Find) | JavaScript (Chromium) | Supports lookahead/lookbehind, \p{L} with u flag auto-applied |
| grep (basic) | POSIX BRE | Needs escaping: \( \) for groups, \{ \} for quantifiers |
| grep -E / egrep | POSIX ERE | Standard syntax, no lookahead/lookbehind |
| grep -P | PCRE | Full PCRE features including lookarounds (Linux only) |
| sed | POSIX BRE (default) | Use sed -E for extended regex. No lookarounds. |
| Python re | Custom (based on PCRE) | Named groups use (?P<name>), fixed-width lookbehind only |
| JavaScript | V8/SpiderMonkey | Variable-width lookbehind since ES2018, no atomic groups |
The biggest gotcha when moving between tools: grep uses POSIX Basic Regular Expressions by default, where ( is a literal character and \( starts a group. In JavaScript and Python, it is the opposite. If your pattern works here but not in grep, try grep -E or grep -P to switch engines.
For a complete reference of all regex syntax, the Regex Cheat Sheet covers every category with try-it examples. For simple text search and replace without regex, the Find and Replace tool is faster. To format structured data after extraction, the JSON Formatter cleans up output. All processing runs in your browser - your test data never leaves your machine.
Sources
Frequently Asked Questions
What regex flags are supported?
This tool supports four standard JavaScript regex flags: g (global, find all matches), i (case-insensitive matching), m (multiline, where ^ and $ match line boundaries), and s (dotAll, where the dot matches newline characters). You can combine multiple flags by checking their respective boxes.
What are capture groups and how do I use them?
Capture groups are portions of a regex pattern enclosed in parentheses. They extract specific parts of a match for individual use. For example, the pattern (\d{3})-(\d{4}) applied to 555-1234 creates two groups containing 555 and 1234 respectively. This tool displays all groups for each match.
Why does my regex work differently here than in my programming language?
This tool uses JavaScript's built-in RegExp engine. While most basic regex syntax is universal, advanced features like lookbehind assertions, atomic groups, and possessive quantifiers may behave differently or be unavailable compared to engines like PCRE (PHP/Python) or .NET regex.
How do I match special characters literally?
Characters with special meaning in regex (such as . * + ? ^ $ { } [ ] ( ) | \) must be escaped with a backslash to match literally. For example, use \. to match a period, \( to match an opening parenthesis, and \\ to match a backslash.
Related Tools
Link to this tool
Copy this HTML to link to this tool from your website or blog.
<a href="https://toolboxkit.io/tools/regex-tester/" title="Regex Tester - Free Online Tool">Try Regex Tester on ToolboxKit.io</a>