regexpatternsjavascript
Mastering Regular Expressions
· Cosyslabs
Regular expressions are a miniature language for describing text patterns. A regex engine tests a pattern against a string and reports matches, positions, and captured groups. Despite having a reputation for being cryptic, regex follows consistent rules — once you internalize the building blocks, you can construct patterns for nearly any text-matching problem.
The Building Blocks
Literal Characters and the Dot
cat matches "cat" exactly
c.t matches "cat", "cbt", "c9t", "c t" (. = any character except newline)
c\.t matches "c.t" only (backslash escapes special meaning)
Character Classes
[aeiou] matches any single vowel
[a-z] matches any lowercase letter
[A-Z0-9] matches any uppercase letter or digit
[^aeiou] matches any character that is NOT a vowel (negated class)
Shorthand classes:
\d digit [0-9]
\D non-digit [^0-9]
\w word character [a-zA-Z0-9_]
\W non-word character
\s whitespace (space, tab, newline, etc.)
\S non-whitespace
Quantifiers
a? zero or one "a"
a* zero or more "a"
a+ one or more "a"
a{3} exactly 3 "a"s
a{2,4} 2 to 4 "a"s
a{2,} 2 or more "a"s
By default quantifiers are greedy — they match as much as possible. Add ? for lazy (minimal) matching:
<.*> greedy: matches "<b>bold</b>" as one match
<.*?> lazy: matches "<b>" then "</b>" as separate matches
Anchors
^pattern matches at start of string (or line with multiline flag)
pattern$ matches at end of string
\bword\b word boundary — matches "word" not inside "password"
\B non-word boundary
Groups and Alternation
(cat|dog) matches "cat" or "dog" (alternation in a group)
(?:cat|dog) non-capturing group (no backreference)
(cat)(dog) two capturing groups
\1 backreference to first group
Flags
// JavaScript flags
/pattern/g — global (find all matches, not just first)
/pattern/i — case-insensitive
/pattern/m — multiline (^ and $ match line boundaries)
/pattern/s — dotAll (. matches newline too)
/pattern/gi — combine flags
JavaScript Regex API
const str = "The price is $42.50 or $18.00";
// test() — returns boolean
/\$[\d.]+/.test(str); // true
// match() — first match (or all with /g)
str.match(/\$[\d.]+/); // ["$42.50", ...]
str.match(/\$[\d.]+/g); // ["$42.50", "$18.00"]
// exec() — iterate matches with groups
const re = /\$(\d+)\.(\d{2})/g;
let m;
while ((m = re.exec(str)) !== null) {
console.log(`Dollars: ${m[1]}, Cents: ${m[2]}`);
}
// Named groups
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const { year, month, day } = "2026-05-20".match(dateRe).groups;
// replace() with regex
str.replace(/\$[\d.]+/g, "PRICE"); // "The price is PRICE or PRICE"
str.replace(/\$(\d+\.\d{2})/g, "USD $1"); // "The price is USD 42.50 or USD 18.00"
// split() with regex
"one two\tthree".split(/\s+/); // ["one", "two", "three"]
Practical Patterns
// Email (basic — full RFC 5322 is much more complex)
const email = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;
// URL
const url = /^https?:\/\/([\w\-]+\.)+[\w\-]+(\/[\w\-./?%&=#]*)?$/;
// IPv4 address
const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
// UUID v4
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
// ISO 8601 date
const isoDate = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;
// Hex color
const hexColor = /^#([0-9a-fA-F]{3}){1,2}$/;
// Semantic version
const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\w.-]+))?(?:\+([\w.-]+))?$/;
// Digits only
const digitsOnly = /^\d+$/;
// Alphanumeric slug
const slug = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
Lookaheads and Lookbehinds
Lookarounds match based on context without consuming characters:
// Positive lookahead: match "foo" only when followed by "bar"
/foo(?=bar)/
// Negative lookahead: match "foo" NOT followed by "bar"
/foo(?!bar)/
// Positive lookbehind: match "bar" preceded by "foo"
/(?<=foo)bar/
// Negative lookbehind: match "bar" NOT preceded by "foo"
/(?<!foo)bar/
// Example: find price numbers (only the digits, not the $ sign)
"$42.50".match(/(?<=\$)[\d.]+/); // ["42.50"]
// Password strength: at least 8 chars, one uppercase, one digit
const strong = /^(?=.*[A-Z])(?=.*\d).{8,}$/;
Python and Go Regex
import re
# Python
pattern = re.compile(r'\b\d{4}-\d{2}-\d{2}\b')
matches = pattern.findall("Dates: 2026-05-20 and 2026-06-01")
# ['2026-05-20', '2026-06-01']
# Named groups
m = re.search(r'(?P<year>\d{4})-(?P<month>\d{2})', '2026-05')
m.group('year') # '2026'
m.group('month') # '05'
// Go — regexp package (RE2 syntax, no lookaheads)
import "regexp"
re := regexp.MustCompile(`\b\d{4}-\d{2}-\d{2}\b`)
matches := re.FindAllString("Dates: 2026-05-20 and 2026-06-01", -1)
// Named groups
re2 := regexp.MustCompile(`(?P<year>\d{4})-(?P<month>\d{2})`)
match := re2.FindStringSubmatch("2026-05")
year := match[re2.SubexpIndex("year")] // "2026"
Tools
- Regex Tester — test regex patterns with live highlighting
- Regex Generator — generate patterns from examples