Regex Tester - Regex Generator & Regular Expression Validator
Use this free online regex tester to build, test, and debug regular expressions directly in your browser — no setup, no installation, no account required. Unlike most tools that run on JavaScript, this tester uses Python's native re engine, which means the patterns you write here will behave exactly the same way in your Python scripts, Django views, Flask routes, and data pipelines. Enter a pattern, paste your test string, choose your flags, and get instant results with match highlighting, capture group breakdowns, and replacement previews.
What Is a Regex Tester and How Does It Work?
What Is a Regular Expression (Regex)?
A regular expression — commonly called a regex or regexp — is a sequence of characters that defines a search pattern. You use that pattern to find, match, validate, or transform text. Regex is not a programming language on its own; it's a compact syntax understood by almost every language, including Python, JavaScript, Java, Go, and PHP. Whether you're validating an email address, extracting log data, or replacing substrings in a file, regex is the tool developers reach for when plain string methods fall short.
What Does an Online Regex Tester Do?
A regex tester gives you a live environment to write and verify patterns without touching your codebase. You write the pattern, paste a test string, and the tool instantly highlights every match, breaks down captured groups, and shows you where in the string each match starts and ends. It's the difference between guessing whether your pattern works and knowing it before you deploy.
For Python developers specifically, this matters more than most people realize. JavaScript regex and Python regex are not the same — they handle named groups, lookaheads, and flag syntax differently. Running your pattern in a JavaScript-based tester and then dropping it into your Python script is a common source of bugs. This tool eliminates that problem entirely.
Why Use an Online Regex Tester Instead of Testing in Code?
- Immediate visual feedback — matches are highlighted in real time, so you see exactly what your pattern captures
- No environment setup — no terminal, no interpreter, no dependencies; works in any browser
- Safe iteration — test edge cases and corner cases without modifying your actual codebase
- Catch errors early — invalid syntax is caught and returned as a readable error message, not a silent failure
- Understand complex patterns — the match breakdown shows numbered and named groups, start/end indices, and replacement output in one view
- Python-accurate results — patterns tested here behave identically in production Python code
How to Use This Online Regex Tester
Using the tool takes less than a minute:
- Enter your regex pattern in the Pattern field. Example:
^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$ - Paste your test string in the Test String field. This can be a single value, a multi-line block of text, or a sample from a real dataset.
- Select your flags — Ignore Case (i), Multiline (m), Dot All (s), Unicode (u), or Verbose (x) — depending on your pattern's requirements.
- Click "Test Regex" to submit the pattern to the Python
reengine. - Review the results across three tabs: Highlight (visual match display), Matches (detailed breakdown), and Replacements (substitution preview).
- Adjust and re-test until the pattern behaves as expected across all your test cases.
Understanding the Three Result Tabs
Highlight Tab Shows your test string with every match highlighted inline. If your pattern has multiple matches across the text, each one is marked visually. This is the fastest way to spot whether your pattern is matching too much, too little, or exactly what you intended.
Matches Tab Gives you the technical detail. For every match, you'll see the exact matched text, the start index (where it begins in the string), the end index (where it ends), and the values of any numbered or named capture groups. If your pattern is (\d{3})-(\d{3})-(\d{4}) and it matches 415-555-0123, group 1 is 415, group 2 is 555, group 3 is 0123.
Replacements Tab Shows a preview of how your string would look after a global substitution using re.sub(). Even without a custom replacement string, the tool auto-generates a group-based preview using MATCH(g1, g2, ...) notation, so you can instantly visualize how data extraction or transformation logic would behave.
Python Regex Tester — Test re Module Patterns Directly in Your Browser
Most online regex testers — including some very popular ones — run on JavaScript's RegExp engine. That's fine if you're writing frontend code. But if you're a Python developer, it's a problem you might not notice until your pattern breaks in production.
Python's re module and JavaScript's regex engine have real differences:
- Named groups use different syntax: Python uses
(?P<name>...)while JavaScript uses(?<name>...) - The
re.VERBOSEflag is Python-only — it has no direct equivalent in JS re.match()only matches at the start of a string — JS has no direct equivalent behavior- Unicode handling works differently across the two engines
- Lookbehind assertions have stricter constraints in Python's standard
remodule
This tool runs Python's native re module on the backend. The pattern you test here is the same one you'd compile with re.compile() in your script — same engine, same behavior, no surprises.
re.match() vs re.search() vs re.findall() — Which One Are You Testing?
This is one of the most common sources of confusion for developers working with Python regex, and none of the major online testers explain it in their tool pages. Here's a clear breakdown:
| Function | What It Does | Returns |
|---|---|---|
re.match(pattern, string) |
Matches only at the start of the string | Match object or None |
re.search(pattern, string) |
Scans the entire string for the first match | Match object or None |
re.findall(pattern, string) |
Returns all non-overlapping matches across the string | List of strings |
re.finditer(pattern, string) |
Like findall, but returns match objects with position info | Iterator of match objects |
This tool uses re.finditer() internally, which gives you the richest output: every match across the full string, with start/end positions and group values for each one. If you need to replicate the behavior of re.match() specifically, use the ^ anchor at the start of your pattern — that constrains matching to the beginning of the string (or each line, when the Multiline flag is on).
Quick example:
python
import re
text = "Order 101 and Order 202 were shipped"
pattern = r"Order (\d+)"
# re.findall — returns ['101', '202']
matches = re.findall(pattern, text)
# re.finditer — returns match objects with position and group info
for m in re.finditer(pattern, text):
print(m.group(0), m.start(), m.end(), m.group(1))
Why Python Regex Behaves Differently Than JavaScript Regex
If you've ever copied a pattern from Stack Overflow and gotten different results in Python than the poster described, there's a good chance they were testing in JavaScript. Here are the concrete differences that trip developers up most often:
1. Named capture group syntax
Python: (?P<year>\d{4})
JavaScript: (?<year>\d{4})
2. Verbose mode (Python only) Python lets you write readable, commented regex using the re.VERBOSE flag. There's no equivalent in vanilla JavaScript:
python
pattern = re.compile(r"""
(\d{4}) # year
-(\d{2}) # month
-(\d{2}) # day
""", re.VERBOSE)
3. re.match() is anchored at the start In Python, re.match() only looks at the beginning of the string. re.search() scans the whole thing. JavaScript's .test() and .exec() always scan the full string.
4. Raw strings matter in Python In Python, always prefix regex patterns with r"" to avoid backslash conflicts. r"\d+" is correct. "\d+" may cause issues because Python processes the backslash before the regex engine sees it.
python
# This can cause unexpected behavior:
pattern = "\d+"
# This is correct:
pattern = r"\d+"
Regex Flags Explained — Ignore Case, Multiline, Dot All, Verbose, and More
Flags modify how your regex engine interprets a pattern. This tool supports all five major Python regex flags, and each one changes behavior in specific ways that are worth understanding — not just knowing the letter abbreviation.
Ignore Case — i / re.IGNORECASE
Makes the pattern case-insensitive. A pattern like [a-z]+ will match both lowercase and uppercase letters when this flag is active.
python
re.findall(r"python", "I love Python and PYTHON", re.IGNORECASE)
# Returns: ['Python', 'PYTHON']
Use this when matching user input, filenames, or any text where capitalization is inconsistent.
Multiline — m / re.MULTILINE
Changes how ^ and $ behave. By default, ^ matches the start of the entire string and $ matches the end. With Multiline on, ^ matches the start of each line and $ matches the end of each line.
python
text = "first line\nsecond line\nthird line"
re.findall(r"^\w+", text, re.MULTILINE)
# Returns: ['first', 'second', 'third']
This is essential when working with log files, CSV data, or any multi-line text where you need to process each line independently.
Dot All — s / re.DOTALL
By default, the . metacharacter matches any character except a newline (\n). With Dot All enabled, . matches everything including newlines.
python
text = "Start\nMiddle\nEnd"
re.search(r"Start.+End", text, re.DOTALL)
# Matches — without re.DOTALL, this returns None
Critical for matching content that spans multiple lines, like HTML blocks, multi-line log entries, or JSON strings.
Unicode — u / re.UNICODE
Makes shorthand classes like \w, \d, and \s match Unicode characters, not just ASCII. In Python 3, this is the default for string patterns. You only need to set it explicitly if you're working with byte patterns or need to override ASCII mode.
Verbose — x / re.VERBOSE
This is the flag that most developers don't know about, and it's genuinely useful for anyone writing complex patterns. Verbose mode lets you add whitespace and comments inside your regex without affecting how it matches. This turns unreadable patterns into self-documenting code.
python
# Without re.VERBOSE — hard to read:
pattern = r"^(?P<year>\d{4})-(?P<month>0[1-9]|1[0-2])-(?P<day>0[1-9]|[12]\d|3[01])$"
# With re.VERBOSE — readable and maintainable:
pattern = re.compile(r"""
^
(?P<year>\d{4}) # 4-digit year
-
(?P<month>0[1-9]|1[0-2]) # month: 01-12
-
(?P<day>0[1-9]|[12]\d|3[01]) # day: 01-31
$
""", re.VERBOSE)
No other free online regex tester documents the Verbose flag with a real example. If you're writing production-grade Python regex, this flag makes your patterns easier to review, maintain, and hand off to teammates.
Regex Quick Reference Cheat Sheet
The following reference covers the core regex syntax supported by Python's re module. Unlike the floating panels in other tools, this is fully readable HTML — bookmark this section and come back whenever you need a quick reminder.
Character Classes and Special Sequences
| Token | Meaning | Example Pattern | Sample Match |
|---|---|---|---|
. |
Any character except newline (use with re.DOTALL to include newlines) |
c.t |
cat, cut, cot |
\d |
Any digit — equivalent to [0-9] |
\d{3} |
415, 007 |
\D |
Any non-digit | \D+ |
hello, abc |
\w |
Word character — letters, digits, underscore | \w+ |
hello_123 |
\W |
Non-word character | \W |
space, @, - |
\s |
Whitespace — space, tab, newline | \s+ |
(spaces) |
\S |
Non-whitespace | \S+ |
word, 123 |
[abc] |
Character class — matches a, b, or c | [aeiou] |
vowels in text |
[^abc] |
Negated class — anything except a, b, or c | [^0-9] |
any non-digit |
[a-z] |
Range — any lowercase letter | [a-zA-Z] |
any letter |
\b |
Word boundary — position between \w and \W |
\bcat\b |
cat but not catch |
\B |
Non-word boundary | \Bcat\B |
cats in concatenate |
^ |
Start of string (or line in Multiline mode) | ^Hello |
lines starting with Hello |
$ |
End of string (or line in Multiline mode) | world$ |
lines ending with world |
Quantifiers — Greedy vs Non-Greedy
| Quantifier | Meaning | Greedy? |
|---|---|---|
* |
0 or more | Yes |
+ |
1 or more | Yes |
? |
0 or 1 | Yes |
{n} |
Exactly n | Yes |
{n,} |
n or more | Yes |
{n,m} |
Between n and m | Yes |
*? |
0 or more | No (non-greedy) |
+? |
1 or more | No (non-greedy) |
?? |
0 or 1 | No (non-greedy) |
Greedy vs non-greedy — the practical difference:
Greedy quantifiers match as much as possible. Non-greedy quantifiers match as little as possible. This distinction matters whenever your text contains repeated delimiters.
python
text = '<a href="link1">click</a> and <a href="link2">here</a>'
# Greedy — matches from first < to last >
re.findall(r"<.+>", text)
# ['<a href="link1">click</a> and <a href="link2">here</a>']
# Non-greedy — matches each tag individually
re.findall(r"<.+?>", text)
# ['<a href="link1">', '</a>', '<a href="link2">', '</a>']
When extracting content between HTML tags, XML elements, or quoted strings, always start with the non-greedy version (+? or *?) and tighten from there.
Anchors — Start, End, and Word Boundaries
Anchors don't match characters — they match positions.
^at the start of a pattern means the match must begin at the start of the string$at the end means the match must end at the end of the string\bmatches the boundary between a word character and a non-word character — useful for matching whole words without capturing partial ones
python
# \b prevents matching "cat" inside "catch" or "concatenate"
re.findall(r"\bcat\b", "The cat sat, but not catch or concatenate")
# Returns: ['cat']
Groups, Capturing, and Alternation
| Syntax | Meaning |
|---|---|
(abc) |
Capturing group — captures the matched text for use in results |
(?:abc) |
Non-capturing group — groups without storing the match |
(?P<name>abc) |
Named capturing group (Python syntax) |
(?P=name) |
Backreference to named group |
a|b |
Alternation — matches a or b |
\1, \2 |
Backreference to numbered group |
Named capture groups are particularly powerful in Python because they let you reference match results by meaningful names instead of numbers:
python
pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
m = re.search(pattern, "Date: 2025-03-15")
print(m.group("year")) # 2025
print(m.group("month")) # 03
print(m.group("day")) # 15
Lookahead and Lookbehind Assertions
Lookarounds let you match text based on what comes before or after it — without including the surrounding context in the match itself. They're one of the most powerful tools in regex, and essential for complex validation patterns.
| Assertion | Syntax | Meaning |
|---|---|---|
| Positive lookahead | (?=...) |
Match if followed by... |
| Negative lookahead | (?!...) |
Match if NOT followed by... |
| Positive lookbehind | (?<=...) |
Match if preceded by... |
| Negative lookbehind | (?<!...) |
Match if NOT preceded by... |
python
# Positive lookahead — match "100" only if followed by " USD"
re.findall(r"\d+(?= USD)", "100 USD and 200 EUR")
# Returns: ['100']
# Negative lookbehind — match digits not preceded by "$"
re.findall(r"(?<!\$)\d+", "cost $50, code 99, ref 123")
# Returns: ['99', '123']
Common Regex Patterns and Real-World Examples
The patterns below are production-ready starting points. Each one is written for Python's re module. Test any of them directly in the tool above — paste the pattern, add a test string, and adjust as needed for your specific requirements.
Regex for Email Validation
^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$
What it matches: Standard email addresses including subdomains, plus signs, dots, and hyphens in the local part. Requires a domain and a TLD of at least 2 characters.
Edge cases: This pattern accepts user+tag@subdomain.example.co.uk (valid) but will not match email addresses with IP-address domains or quoted local parts as defined in the full RFC 5322 specification. For most application-level validation, this is sufficient.
python
import re
pattern = r"^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$"
emails = ["user@example.com", "bad@", "name+tag@mail.co.uk"]
valid = [e for e in emails if re.match(pattern, e)]
# Returns: ['user@example.com', 'name+tag@mail.co.uk']
Regex for Phone Number Matching
\b(\+?1[-.\s]?)?(\(?\d{3}\)?[-.\s]?)(\d{3}[-.\s]?\d{4})\b
What it matches: US phone numbers in formats like 415-555-0123, (415) 555-0123, 4155550123, and +1 415 555 0123.
Note: For international numbers beyond the US, use a library like phonenumbers rather than regex — the format variation is too large for a single maintainable pattern.
Regex for URL Validation
https?://(?:www\.)?[a-zA-Z0-9\-]+(?:\.[a-zA-Z]{2,})+(?:/[^\s]*)?
What it matches: HTTP and HTTPS URLs with optional www, a domain, and an optional path. Handles most real-world URLs found in logs, form inputs, and scraped content.
Regex for IPv4 Address Matching
\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b
What it matches: Valid IPv4 addresses from 0.0.0.0 to 255.255.255.255. Each octet is validated to be within range — 999.1.1.1 will not match.
Regex for Date Format Matching (YYYY-MM-DD)
\b(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\b
What it matches: ISO 8601 dates like 2025-03-15. The month is constrained to 01–12 and the day to 01–31. For MM/DD/YYYY format, swap the group order and replace - with /.
Regex for Password Strength Validation
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&\-_#])[A-Za-z\d@$!%*?&\-_#]{8,}$
What it matches: Passwords that are at least 8 characters long and contain at least one lowercase letter, one uppercase letter, one digit, and one special character.
This pattern uses four positive lookaheads ((?=...)) — each one checks for a condition without consuming characters. This is a perfect real-world use case for the lookahead section of the cheat sheet above.
Regex for Extracting HTML Tags
<([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>(.*?)</\1>
What it matches: Opening tags, their inner content, and the matching closing tag using a backreference (\1). Works for well-formed HTML.
Important note: Regex is not a full HTML parser and will fail on nested tags of the same type or malformed markup. For production HTML parsing, use BeautifulSoup or lxml. Use this pattern for simple content extraction and one-off text processing tasks.
Regex for Log File Parsing (Apache/Nginx Access Logs)
^(\S+) \S+ \S+ \[([^\]]+)\] "(\S+) (\S+)[^"]*" (\d{3}) (\d+)
Captures:
- Group 1: Client IP address
- Group 2: Timestamp
- Group 3: HTTP method (GET, POST, etc.)
- Group 4: Request path
- Group 5: HTTP status code
- Group 6: Response size in bytes
python
import re
log_line = '192.168.1.1 - - [15/Mar/2025:10:22:01 +0000] "GET /api/users HTTP/1.1" 200 1523'
pattern = r'^(\S+) \S+ \S+ \[([^\]]+)\] "(\S+) (\S+)[^"]*" (\d{3}) (\d+)'
m = re.match(pattern, log_line)
if m:
print(f"IP: {m.group(1)}, Status: {m.group(5)}, Bytes: {m.group(6)}")
# IP: 192.168.1.1, Status: 200, Bytes: 1523
Regex for Username Validation
^[a-zA-Z0-9_]{3,16}$
What it matches: Usernames between 3 and 16 characters, containing only letters, numbers, and underscores. Clean, readable, and enforces consistent formatting without a complex pattern.
Regex for Extracting Hashtags
#[A-Za-z0-9_]+
What it matches: Social media hashtags anywhere in a string. Works on Twitter/X, Instagram, and any custom tagging system. Use re.findall() to extract all hashtags from a block of text at once.
Regex Tester — Frequently Asked Questions
What regex engine does this tool use?
This tool runs Python's built-in re module on the backend. All matching, searching, and substitution follow Python regex behavior exactly — the same as re.compile(), re.finditer(), and re.sub() in your scripts. This makes it reliable for backend development in Django, Flask, FastAPI, and standalone Python automation.
What is the difference between re.match() and re.search() in Python?
re.match() only checks for a match at the beginning of the string. If your pattern doesn't match the very first characters, it returns None. re.search() scans the entire string and returns the first match found anywhere. For most practical use cases — like finding a pattern in a log line or a block of text — re.search() or re.finditer() is the right choice. This tool uses re.finditer() internally, which finds all matches across the full test string.
How do I test a Python regex pattern in my browser?
Paste your pattern into the Pattern field above, enter your test string, select any flags your code uses (like re.IGNORECASE → Ignore Case i), and click Test Regex. The result is computed by Python's actual re module — not a JavaScript approximation — so you can trust the output matches what your code will produce.
What does \d, \w, and \s mean in a regular expression?
\dmatches any digit (0–9). Equivalent to the character class[0-9]\wmatches any word character — letters (a–z, A–Z), digits (0–9), and underscore (_). Equivalent to[a-zA-Z0-9_]\smatches any whitespace character — space, tab (\t), newline (\n), carriage return (\r), and form feed (\f)
Their uppercase counterparts (\D, \W, \S) match the opposite — any character that is NOT a digit, word character, or whitespace, respectively.
What is a greedy quantifier and when should I use a non-greedy one?
Greedy quantifiers (*, +, {n,m}) match as many characters as possible. Non-greedy versions (*?, +?, {n,m}?) match as few as possible. The practical rule: if you're extracting content between two delimiters (HTML tags, quotes, brackets) and getting too much content in the match, switch from .* to .*?. Non-greedy is almost always the right default when your delimiters can repeat in the text.
Can I use this regex tester for Python scripts and Django projects?
Yes — and it's specifically designed for that. Because the backend uses Python's re module, patterns you verify here are guaranteed to work the same way in your Django views, Flask routes, Python scripts, and data pipelines. Named capture groups use Python's (?P<name>...) syntax, and all five Python regex flags are supported.
What are named capture groups in regex and how do I use them in Python?
Named capture groups let you assign a label to a part of your pattern so you can reference match results by name instead of by index number. In Python, the syntax is (?P<groupname>pattern). After a match, you access it with m.group("groupname"). This makes your code significantly more readable when dealing with patterns that have multiple groups, like date parsers or log extractors.
How do I make a regex pattern case-insensitive?
Enable the Ignore Case (i) flag in the tool above — this corresponds to re.IGNORECASE in Python. You can also apply it inline in the pattern itself with (?i) at the start: (?i)hello matches hello, Hello, HELLO, and every other capitalization. The inline version is useful when you need the flag to apply only to part of a pattern.
What is the Verbose flag (x / re.VERBOSE) in Python regex?
The Verbose flag (re.VERBOSE or flag x) lets you write multi-line regex with whitespace and comments, without those spaces and comments becoming part of the pattern. This is a Python-specific feature with no JavaScript equivalent. It's useful for any complex pattern you need to maintain or share with other developers — instead of one dense unreadable string, you get a structured, commented expression. See the full explanation with code examples in Section 5 above.
How do I match a newline character with regex?
By default, the . metacharacter does not match newlines. To make it match newlines, enable the Dot All (s) flag — this corresponds to re.DOTALL in Python. Alternatively, you can use [\s\S]+ as your pattern, which explicitly matches any character including newlines, and works even without the flag.
Does this tool store my regex patterns or test strings?
No. Your pattern and test string are sent via an encrypted POST request, processed immediately by the Python re engine, and the result is returned to your browser. Nothing is stored in a database, logged to a file, or retained in memory after the response is sent. Your intellectual property — including proprietary patterns you use in your codebase — stays private.
What happens if my regex syntax is invalid?
If your pattern contains a syntax error, the Python backend catches the exception and returns the specific error message directly in the results area. You'll see the exact error Python would throw — for example, error: missing ), unterminated subpattern at position 5 — which makes it much easier to locate and fix the problem than a generic "invalid pattern" message.