Regex Guide: Complete Regular Expression Tutorial for Beginners

๐Ÿ“… June 22, 2026 ยท โ˜• 10 min read ยท Jump to FAQ โ†“

Regular expressions (regex) are one of the most powerful tools in a developer's toolkit. Whether you're validating forms, parsing log files, searching through code, or extracting data from messy text โ€” regex gets it done faster than anything else.

But let's be honest: regex has a steep learning curve. Those cryptic patterns like ^[\\w.-]+@[\\w.-]+\\.\\w{2,}$ look like line noise. The good news? Once you understand the building blocks, it all clicks into place.

This guide covers everything you need to know: from basic characters all the way to advanced lookarounds, with examples you can test right now using our free online regex tester.

What Is a Regular Expression?

A regular expression is a sequence of characters that forms a search pattern. Think of it as a mini programming language for string matching. You can use regex to:

Regular expressions are supported in virtually every programming language โ€” JavaScript, Python, Java, PHP, Go, Ruby, and more โ€” with only minor syntax variations.

Regex Syntax Basics

Literal Characters

Most characters in a regex match themselves. The pattern cat matches the string "cat" wherever it appears.

Pattern: cat
Matches: "cat" โœ“  "concatenate" โœ“  "scatter" โœ“
No match: "dog" โœ—  "cot" โœ—

Metacharacters

These special characters have meaning beyond their literal value and need escaping with \\ to match literally:

CharMeaning
.Any character except newline
^Start of string / line
$End of string / line
*Zero or more of preceding element
+One or more of preceding element
?Zero or one (optional) of preceding element
{}Exact count / range quantifier
[]Character class (one of)
()Group / capture
|OR operator (alternation)
\\Escape next character / shorthand class

Character Classes

Character classes match one character from a set:

PatternMeaningExample
[abc]a, b, or cMatches "a" in "apple"
[a-z]Any lowercase letterMatches "t", "e", "s", "t" in "test"
[0-9]Any digitMatches "4" and "2" in "v4.2"
[^abc]NOT a, b, or cMatches "x" in "axbxc"

Shorthand Character Classes

ShorthandEqualsMatches
\\d[0-9]A digit
\\w[a-zA-Z0-9_]A word character (letter, digit, underscore)
\\s[ \\t\\n\\r\\f\\v]A whitespace character
\\D[^0-9]NOT a digit
\\W[^a-zA-Z0-9_]NOT a word character
\\S[^ \\t\\n\\r\\f\\v]NOT whitespace

Example: \\d{3}-\\d{4} matches phone number segments like 555-1234.

Quantifiers

Quantifiers specify how many times the preceding element must appear:

QuantifierMeaningExample
*Zero or moreab*c matches "ac", "abc", "abbc"
+One or moreab+c matches "abc", "abbc" but not "ac"
?Zero or oneab?c matches "ac", "abc" but not "abbc"
{3}Exactly 3\\d{3} matches "555"
{2,4}2 to 4\\d{2,4} matches "55", "555", "5555"
{3,}3 or more\\d{3,} matches "555", "5555", ...

Greedy vs Lazy Matching

By default, quantifiers are greedy โ€” they match as much as possible. Adding a ? after the quantifier makes it lazy, matching as little as possible.

String: <b>bold</b><i>italic</i>

Greedy: <.+>  โ†’  matches "<b>bold</b><i>italic</i>" (the whole thing)
Lazy:   <.+?> โ†’  matches "<b>" (just the first tag)

This is one of the most common sources of bugs in regex. When extracting HTML tags, comments, or any delimited content, always use lazy quantifiers unless you specifically want the greedy behavior.

Anchors

Anchors don't match characters โ€” they match positions within the string:

AnchorMeaning
^Start of string (or line in multiline mode)
$End of string (or line in multiline mode)
\\bWord boundary (start or end of a word)
\\BNOT a word boundary

Example: ^hello matches "hello" only at the beginning of the string. world$ matches "world" only at the end. \\bcat\\b matches "cat" as a whole word but not in "catalog".

Alternation (OR)

The pipe | acts as an OR operator:

cat|dog     โ†’  matches "cat" or "dog"
gray|grey   โ†’  matches both "gray" and "grey"
Mon|Tue|Wed โ†’  matches any of the three

Use parentheses to limit alternation scope: gr(a|e)y matches "gray" and "grey" more precisely.

Groups and Capturing

Capturing Groups ()

Parentheses create capturing groups that extract specific parts of a match:

Pattern: (\\d{3})-(\\d{4})
String:  Phone: 555-1234
Match:   "555-1234"
Group 1: "555"
Group 2: "1234"

Captured groups can be used in replacement operations:

Find:    (\\w+)@(\\w+)
Replace: $1 [at] $2
Result:  john@example โ†’ john [at] example

Named Groups

Modern regex engines support named groups for readability:

(?<name>pattern)        โ€” Named capture group
Pattern: (?<area>\\d{3})-(?<num>\\d{4})
Replace: ${area}-${num}
Matches: "555-1234" with named groups "area"="555" and "num"="1234"

Non-Capturing Groups (?:)

Use (?:) when you need grouping but don't need to capture:

Pattern: (?:\\d{3}-)?\\d{4}
Matches: "555-1234" and "1234" โ€” groups without capturing overhead

Lookahead and Lookbehind (Lookarounds)

Lookarounds are zero-width assertions โ€” they check for a pattern without including it in the match. These are essential for complex validations.

TypeSyntaxExample
Positive lookahead(?=...)\\d(?=px) matches digit followed by "px"
Negative lookahead(?!...)\\d(?!px) matches digit NOT followed by "px"
Positive lookbehind(?<=...)(?<=\\$)\\d+ matches digits preceded by "$"
Negative lookbehind(?<!...)(?<!\\$)\\d+ matches digits NOT preceded by "$"

Practical examples:

# Extract prices (digits preceded by $)
(?<=\\$)\\d+(\\.\\d{2})?
โ†’ "$29.99" matches "29.99", "โ‚ฌ29.99" no match

# Password validation (must contain uppercase, digit, special char)
^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$
โ†’ "P@ssw0rd!" โœ“  "password" โœ—

# Find "cat" but not "catalog"
\\bcat\\b
โ†’ "cat" โœ“  "catalog" โœ— (partial "cat")

Common Regex Patterns Cheat Sheet

PatternMatches
^[\\w.-]+@[\\w.-]+\\.\\w{2,}$Email (basic)
https?://[\\w./-]+URL (basic)
^\\+?\\d{1,3}[-. ]?\\d{3,14}$Phone number
^\\d{4}-\\d{2}-\\d{2}$Date (YYYY-MM-DD)
^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$IPv4 address (basic)
#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})Hex color code
(?<=\\/\\/)[^\\/]+Domain from URL
\\b\\w{6,}\\bWords with 6+ characters

Regex in Popular Programming Languages

JavaScript

// Test if string contains a pattern
/test/i.test("Hello World");      // โ†’ false
/hello/i.test("Hello World");     // โ†’ true (i = case-insensitive)

// Extract matches
"The price is $29.99".match(/\\$\\d+\\.\\d{2}/); // โ†’ ["$29.99"]

// Replace
"hello@example.com".replace(/(\\w+)@(\\w+)/, "$1 [at] $2");
// โ†’ "hello [at] example"

Python

import re

# Test match
re.search(r'hello', 'Hello World', re.I)  # โ†’ match object

# Find all matches
re.findall(r'\\d+', 'App v2.5 released in 2026')
# โ†’ ['2', '5', '2026']

# Replace
re.sub(r'(\\w+)@(\\w+)', r'\\1 [at] \\2', 'john@test.com')
# โ†’ 'john [at] test'

PHP

// Test if pattern exists
preg_match('/hello/i', "Hello World");  // โ†’ 1 (true)

// Extract all matches
preg_match_all('/\\d+/', 'App v2.5', $matches);
// $matches[0] = ['2', '5']

// Replace
preg_replace('/(\\w+)@(\\w+)/', '$1 [at] $2', 'john@test.com');
// โ†’ 'john [at] test'

Common Regex Pitfalls and How to Avoid Them

1. Forgetting to Escape Special Characters

To match a literal dot, use \\. not just .. The unescaped dot matches any character โ€” a.com would match "aXcom" too.

2. Greedy Quantifiers in Wrong Places

This is the #1 regex bug. When extracting content between delimiters, always consider whether you need lazy (*?, +?) or greedy (*, +) matching.

3. Overly Complex Expressions

A 200-character regex is harder to debug than 3 simple ones. Break complex patterns into steps. For email validation, consider using your language's built-in validator instead โ€” the full email RFC regex is notoriously monstrous.

4. Catastrophic Backtracking

Patterns like (a+)+b can cause catastrophic backtracking on non-matching strings like "aaaaac". The nested quantifiers create exponential states. Avoid (x+)+ and (x*)* patterns.

5. Not Anchoring Your Patterns

\\d{3} matches "555" anywhere in the string. ^\\d{3}$ matches only if the entire string is exactly 3 digits. Always use ^ and $ anchors for validation.

Test Your Regex Patterns

The best way to learn regex is to practice with real-time feedback. Try our free online regex tester โ€” enter patterns and see matches instantly:

๐Ÿงช Test Your Regex Patterns Now

Free, fast, and private โ€” no data uploads, instant results.

Open Regex Tester โ†’

Frequently Asked Questions

What is a regular expression?

A regular expression (regex) is a sequence of characters that defines a search pattern. It's used for pattern matching within strings โ€” validating formats like emails and phone numbers, extracting data, finding and replacing text, and splitting strings. Most programming languages and text editors support regular expressions.

How do I test a regular expression online?

You can test regex patterns online for free using Tools VersionMan's Regex Tester. Simply enter your regex pattern, choose your test string, and see real-time match results with highlighted matches, capture groups, and detailed match information โ€” all processed locally in your browser.

What does \\d+ mean in regex?

In regex, \\d matches any digit (0-9), and the + quantifier means "one or more". So \\d+ matches one or more consecutive digits โ€” integers of any length like 42, 123, or 9999. This is one of the most commonly used regex patterns.

What's the difference between greedy and lazy matching?

Greedy matching (default) tries to match as much text as possible. Lazy matching, indicated by adding ? after a quantifier (like *? or +?), tries to match as little as possible. For example, <.+> applied to <b>bold</b> matches the entire string greedily, while <.+?> matches just <b>. Choosing the right mode is crucial for accurate pattern matching.

What are regex capture groups?

Capture groups are parts of a regex pattern enclosed in parentheses () that extract specific portions of a match. For example, (\\d{3})-(\\d{4}) applied to "555-1234" captures "555" and "1234" separately. Groups can be referenced by number ($1, $2) or name (?<name>...) for replacement operations. Non-capturing groups (?:...) group without capturing.