Overview

Use a real parser when one exists (URLs, dates, HTML, JSON); use regex for small, flat text. Flavors differ: PCRE and Python are Perl-like, JavaScript has its own rules, and POSIX tools (grep -E, sed -E) lack \d and lookarounds. Python specifics are on python-regex; patterns below were tested in Python 3.11 and Node 22.

Syntax

Check which engine you target; spelling and support differ.

SyntaxMeaning
.Any character except newline (any with the s flag).
\d \w \s and \D \W \SDigit, word, whitespace; negated forms.
[abc] [^abc] [a-z]Set, negated set, range.
^ $Start and end of input; of each line with m.
\b \BWord boundary, non-boundary.
\A \ZAbsolute start and end in Python. PCRE uses \A \z (its \Z also matches before a final newline). Not in JavaScript.
? * + {n} {n,} {n,m}Quantifiers; add ? for lazy: *?, +?, {n,m}?.
*+ ++ (?>...)Possessive and atomic (PCRE, Java, Python 3.11+; not JavaScript).
(...) (?:...)Capturing and non-capturing group.
(?<n>...) / (?P<n>...)Named group: JavaScript and PCRE / Python.
\1 \k<n> (?P=n)Backreferences: numbered / JavaScript named / Python named.
(?=...) (?!...) (?<=...) (?<!...)Lookahead and lookbehind, positive and negative; \d+(?= dollars) matches the digits only, (?<=\$)\d+ the digits after $.
a|bAlternation.

Flags by engine

Set flags explicitly per engine rather than assuming parity.

EffectPythonJavaScriptPCRE inline
Case-insensitivere.Ii(?i)
^ $ per linere.Mm(?m)
. matches newlinere.Ss(?s)
Ignore pattern whitespace and commentsre.Xnot available(?x)
Find all matchesfindall, finditergengine API
Unicode matchingdefault for stru (or v)engine option, such as (*UTF)
\p{...} property classesnot in re; use the regex moduleneeds u or vsupported
Sticky match at an indexpattern.match(s, pos)y\G
Match indicesnot availablednot available
ASCII-only classesre.Adefaultengine option

Patterns

Anchor validation patterns; in Python use re.fullmatch.

TargetPattern
IPv4^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$
Port 1-65535^([1-9]\d{0,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$
ISO date^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ (checks ranges, not Feb 30)
RFC 3339 datetime^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)$
UUID, versions 1 to 8^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ (use 4 for v4 only)
Hex color^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
Slug^[a-z0-9]+(?:-[a-z0-9]+)*$
# Email (pragmatic; confirm real addresses by sending mail)
^[\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$

# URL (http and https; catches obvious garbage only)
^https?://[^\s/$.?#].[^\s]*$

Use a parser for the rest: URL in JavaScript, urllib.parse and ipaddress in Python. A naive (\d{1,3}\.){3}\d{1,3} accepts 999.999.999.999, and a short IPv6 regex rejects ::.

Gotchas

Avoid these; each matches too much, too little, or hangs.

GotchaFix
Python $ also matches before a trailing newline.Use fullmatch or \Z.
\d matches any Unicode digit in Python str patterns but only 0-9 in JavaScript, and POSIX -E has no \d.Write [0-9] when you mean ASCII digits everywhere.
A JavaScript /g regex keeps lastIndex, so .test() alternates results across calls.Drop g for tests, or reset lastIndex.
Python lookbehind must be fixed-width; JavaScript allows variable width.Restructure, or use the third-party regex module.
POSIX tools have no lookaround.Use grep -P (GNU only) or perl -ne.
Nested quantifiers like (a+)+ backtrack catastrophically.Simplify the pattern and cap input length.
An unanchored validation pattern matches inside longer text.Anchor with ^ and $.