Regex basics — patterns, groups, quantifiers, boundaries, and safe matching

A regular expression describes a text-matching rule

A regular expression, usually shortened to regex, is a pattern interpreted by a regex engine. Applications use patterns to search, extract, split, replace, and validate text. The engine scans candidate positions and attempts to satisfy the pattern according to its matching rules.

Regex syntax is not perfectly universal. JavaScript, Python, Java, .NET, PCRE, POSIX tools, and editors differ in supported groups, lookbehind, flags, escaping, and replacement syntax. Identify the language and engine before copying a pattern from another environment.

Most characters match themselves; metacharacters control the pattern

Letters and digits usually match the same characters in the input. Characters such as ., *, +, ?, parentheses, brackets, braces, anchors, and the backslash have structural meaning. Escape a metacharacter when it must be matched literally.

There may be two escaping layers: the programming-language string and the regex engine. A JavaScript regex literal /\d+/ contains one backslash, while the equivalent string passed to new RegExp needs "\\d+" so the engine receives that same backslash.

# Pattern: match a literal dot followed by digits
\.\d+

# Matches
.42
.2026

Classes match one character from a defined set

[abc] matches one of three characters, while [^abc] matches one character outside that set. Ranges such as [A-Z] depend on character ordering and usually cover only ASCII. Shorthands such as \d, \w, and \s can have Unicode-dependent behavior across engines.

Use explicit classes when the accepted alphabet is part of a data contract. For international text, check whether the engine supports Unicode properties such as \p{L} and whether the required Unicode flag is enabled.

^[A-Z]{2}-[0-9]{4}$

# Matches an ASCII code such as:
AB-2048

Quantifiers repeat the preceding token or group

* means zero or more, + means one or more, and ? means zero or one. Braces express exact or bounded counts. Quantifiers are greedy by default in many engines: they initially consume as much as possible and backtrack when the rest of the pattern cannot match.

Place repeated structure inside a group. ab+ repeats only b, whereas (?:ab)+ repeats the two-character sequence. Use a noncapturing group when the grouping is structural and the substring does not need to be returned.

Capturing groups return meaningful parts of a match

Parentheses group pattern operations and, by default, capture the matched substring. Numbered captures are referenced by position, which becomes fragile when groups are inserted earlier in a pattern. Named groups make extraction and replacement intent clearer when the engine supports them.

^(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})$

# Input
2026-07-19

# Captures
year=2026 month=07 day=19

Anchors assert a position instead of consuming text

^ and $ commonly represent the start and end of an input, but multiline mode may make them operate at line boundaries. Some engines provide absolute input anchors with different names. A word boundary \b asserts a transition between word and non-word characters and inherits the engine definition of a word character.

Validation patterns normally need anchors around the entire allowed format. Without anchors, a pattern can succeed because one valid-looking substring exists inside otherwise invalid input.

# Search: finds a date inside longer text
[0-9]{4}-[0-9]{2}-[0-9]{2}

# Shape validation: requires the entire input to have that form
^[0-9]{4}-[0-9]{2}-[0-9]{2}$

Flags change how the same pattern is interpreted

Common flags enable case-insensitive matching, global iteration, multiline anchors, dot matching across line breaks, or Unicode-aware behavior. A global flag may also change API state or return shape. Read the host-language API documentation instead of treating flags as portable suffixes.

Replacement syntax is a separate language

A replacement usually refers to captured groups, but the notation differs: environments may use $1, \1, or named forms. Test the replacement API as well as the matching pattern. Escaping rules for a shell, JSON file, programming-language string, and replacement template can all apply at once.

# Pattern
^([^,]+),\s*([^,]+)$

# Input
Lovelace, Ada

# Replacement in a $1-style API
$2 $1

Test examples, near misses, and long adversarial input

A useful regex test set includes expected matches, expected failures, empty input, boundary lengths, Unicode text, and strings that almost match. Regex validates textual shape, not real-world meaning: a date-shaped string can still name an impossible calendar date, and an email-like string does not prove the mailbox exists.

Ambiguous nested repetition can cause excessive backtracking and poor performance. Prefer bounded input, specific character classes, and unambiguous structure. Avoid patterns such as nested broad quantifiers when matching untrusted long text, and measure worst-case behavior in the actual engine.