Back to Blog
RegexPatternsStrings

A Practical Guide to Regular Expressions for Developers

March 20, 2026 · 8 min read

Regular expressions are one of those tools that feel arcane at first but become indispensable once you know them. This guide skips the theory and focuses on the patterns you'll actually use — with working examples you can test right now.

The Basics: Literals and Metacharacters

At its simplest, a regex is just a string to search for. The pattern hello matches the literal text "hello" anywhere in a string. The power comes from metacharacters — special characters with meaning:

CharacterMeaning
.Any single character (except newline)
^Start of string
$End of string
*0 or more of the preceding
+1 or more of the preceding
?0 or 1 of the preceding (optional)
|Or (alternation)
\\Escape a metacharacter

Character Classes

Square brackets define a set of characters to match. Only one character from the set matches at that position.

PatternMatches
[abc]'a', 'b', or 'c'
[^abc]Any character except 'a', 'b', 'c'
[a-z]Any lowercase letter
[A-Z]Any uppercase letter
[0-9]Any digit
\dAny digit (shorthand for [0-9])
\wWord character [a-zA-Z0-9_]
\sWhitespace (space, tab, newline)
\DNon-digit
\WNon-word character
\SNon-whitespace

Quantifiers

QuantifierMeaning
{n}Exactly n times
{n,}n or more times
{n,m}Between n and m times
*0 or more (greedy)
+1 or more (greedy)
*?0 or more (lazy — match as few as possible)
+?1 or more (lazy)

Groups and Capturing

Parentheses create groups. Groups let you capture parts of a match and apply quantifiers to multiple characters at once.

// Capturing group — captures "2024" from "2024-03-31"
(d{4})-d{2}-d{2}

// Non-capturing group — groups without capturing
(?:d{4})-d{2}-d{2}

// Named capturing group
(?<year>d{4})-(?<month>d{2})-(?<day>d{2})

In JavaScript, named groups are accessed via match.groups.year.

Lookaheads and Lookbehinds

Lookarounds assert what comes before or after a position without consuming characters.

SyntaxType
x(?=y)x followed by y (positive lookahead)
x(?!y)x not followed by y (negative lookahead)
(?<=y)xx preceded by y (positive lookbehind)
(?<!y)xx not preceded by y (negative lookbehind)

Real-World Patterns

Email address (simplified)

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$

URL

https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]*)

ISO date (YYYY-MM-DD)

^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$

IPv4 address

^((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)$

Hex color code

^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$

Semantic version (semver)

^(0|[1-9]d*).(0|[1-9]d*).(0|[1-9]d*)(-[a-zA-Z0-9.-]+)?(+[a-zA-Z0-9.-]+)?$

Flags

FlagEffect
gGlobal — find all matches, not just the first
iCase-insensitive matching
mMultiline — ^ and $ match start/end of each line
sDotall — . matches newlines too
uUnicode support

Test Your Patterns

Use the Regex Tester on io9.me to test patterns live with real input, see capture groups highlighted, and get instant feedback as you type.