What Is a Regular Expression? Regex Patterns Explained With Examples
Build a pattern from a clear text requirement rather than treating the punctuation as a shortcut.
Key takeaways
- A regular expression describes text patterns for matching, extraction, and replacement.
- Searching within a string and checking the entire input require different boundaries.
- Flags and engine-specific behavior are part of the pattern's meaning.
- A match does not establish semantic validity, and short patterns can still be expensive.
A regular expression, usually called regex, is a pattern used to search, extract, or transform text.
Instead of searching for one exact string, it describes a family of strings. For example, a support reference might consist of two uppercase letters, a hyphen, and four digits.
That requirement can match AB-4821 and ZX-0007 without listing every possible reference.
The examples here use JavaScript. Other regex engines can differ in syntax and behavior.
Build the Pattern From Small Parts
[A-Z]{2}-[0-9]{4}
Read the expression from left to right:
| Part | Meaning |
|---|---|
[A-Z] | One uppercase ASCII letter |
{2} | Repeat the preceding item exactly twice |
- | A literal hyphen in this position |
[0-9] | One ASCII digit |
{4} | Repeat it exactly four times |
The JavaScript regex guide documents these building blocks.
A character class selects one character. It does not match the whole sequence written inside the brackets.
Searching and Whole-Input Checking Differ
A search can find the reference inside a sentence:
const match = /[A-Z]{2}-[0-9]{4}/.exec("Reference: AB-4821");
console.log(match?.[0]); // AB-4821
For a form field that should contain only the reference, boundaries matter:
const referencePattern = /^[A-Z]{2}-[0-9]{4}$/;
function isReference(value) {
return typeof value === "string" &&
value.length === 7 &&
referencePattern.test(value);
}
This version explicitly requires seven characters as well as the pattern. It rejects surrounding spaces and line breaks.
Normalization is a separate product decision. If spaces should be trimmed, do so deliberately and explain that behavior rather than letting different callers normalize differently.
Capturing Groups Return Useful Pieces
Parentheses can capture part of a match:
const match = /^([A-Z]{2})-([0-9]{4})$/.exec("AB-4821");
if (match) {
console.log(match[1]); // AB
console.log(match[2]); // 4821
}
The captured digits are text. Converting them to a number would remove leading zeros, which may be wrong for a reference identifier.
Use captures when later code needs the components. Use noncapturing groups, written (?:...), when grouping is needed only to organize the pattern.
A captured prefix still does not prove that the support system recognizes that prefix.
Quantifiers Specify How Much
Common repetition forms include + for one or more, * for zero or more, ? for optional, and a range such as {2,5}.
The distinction between zero and one matters. A field intended to contain digits should not accidentally accept an empty string because its pattern used *.
Alternation uses | to express alternatives. Group it carefully so surrounding conditions apply to the intended alternatives.
The regex builder guide provides a more guided way to construct patterns.
Flags Change Behavior
An i flag makes matching case-insensitive. A g flag supports finding successive matches. Other flags affect line boundaries, dot matching, and Unicode behavior.
JavaScript expressions with g or y maintain a lastIndex position during operations such as test(). Reusing one as a simple validator can produce surprising alternating results.
The test() documentation explains that stateful behavior. The reference validator above does not need either flag.
Also remember that [A-Z] is an ASCII range, not a definition of all letters in every language.
Matching Shape Is Only One Check
A date-shaped pattern can accept an impossible date. A reference-shaped string can name an order that does not exist.
After pattern matching, application logic may need to check allowed values, ownership, or database records.
For nested JSON or HTML, use a parser to recover structure, then apply small patterns to appropriate values. The regex-versus-parsing comparison explains this division.
Consider Failure Cases and Cost
Backtracking engines can spend excessive time exploring ambiguous repetitions. A pattern such as ^(a+)+$ can perform badly on some long, nearly matching inputs.
OWASP’s ReDoS explanation describes this class of problem.
Keep untrusted input bounded and avoid needlessly ambiguous patterns. Review failures as well as successes: missing digits, extra characters, empty input, unexpected Unicode, and long near-matches.
For the support reference, a small pattern plus an explicit input contract is easy to explain. That clarity is more valuable than a clever expression whose accepted inputs nobody can confidently describe.
Define what should match and what should fail before trying to shorten the expression.
More Articles Like This

Regex vs Parsing: Choosing the Right Tool for Structured Text
What Is Python? A Practical Introduction to the Language
What Is YAML? Reading the Structure Behind Configuration Files
What Is an Algorithm? Steps, Correctness, and Efficiency Explained
Base64 vs Hex Encoding: Size, Byte Handling, and When to Use Each
