JavaScript Regex
Learn JavaScript regular expressions (regex): how to create patterns, the flags that change matching, and the core methods for searching and validating text.
Introduction to Regular Expressions (Regex) in JavaScript
Regular expressions, commonly known as regex, are sequences of characters that form search patterns. They are essential tools in programming for text processing tasks like searching, editing, and manipulating string data. Regex is used in various fields such as data validation, parsing, syntax highlighting, and more.
For example, you can quickly check whether a string looks like an email address:
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test("[email protected]")); // true
console.log(emailRegex.test("not-an-email")); // falseNote: This is a simplified pattern. For production validation, consider stricter rules or dedicated libraries.
Where regex is used:
- Web development: validating form inputs, parsing URLs, and searching within content.
- Data analysis: extracting specific patterns from large datasets.
- Text editing: finding and replacing text in documents or codebases.
- Programming languages: most modern languages, including JavaScript, support regex.
Creating a regular expression
JavaScript gives you two ways to create a regex, and the difference matters in practice.
// 1. Literal syntax — compiled once when the script loads.
const re1 = /\d+/g;
// 2. Constructor — useful when the pattern is built from a variable.
const word = "cat";
const re2 = new RegExp(word + "s?", "i"); // matches "cat" or "cats", case-insensitive
console.log(re1 instanceof RegExp); // true
console.log(re2.source, re2.flags); // cats? iUse the literal form for fixed patterns — it is shorter and the engine compiles it ahead of time. Reach for the RegExp constructor when the pattern is dynamic (for example, built from user input). Remember that in a string you must double the backslash: "\\d" in a constructor equals \d in a literal.
How regex connects to strings: the core methods
A pattern is only useful together with a method that runs it. These are the ones you will use every day.
const text = "The year 2023 follows 2022.";
// test() → boolean: "does it match anywhere?"
console.log(/\d{4}/.test(text)); // true
// String.match() with /g → array of all matches
console.log(text.match(/\d{4}/g)); // [ '2023', '2022' ]
// String.replace() → returns a new string
console.log(text.replace(/\d{4}/g, "YEAR")); // The year YEAR follows YEAR.
// RegExp.exec() → one match at a time, with capture groups
console.log(/(\d{4})/.exec(text)[1]); // 2023
// String.matchAll() → iterator of full match objects (needs /g)
for (const m of text.matchAll(/(\d{4})/g)) {
console.log(m[0], "at index", m.index);
}
// 2023 at index 9
// 2022 at index 22Pick the method by intent: test() for a yes/no check, match()/matchAll() to extract data, and replace() to rewrite text. The g (global) flag is what turns "the first match" into "every match", so it is essential for match, matchAll, and replace-all operations.
Reading a pattern: common building blocks
Most patterns are assembled from a small vocabulary. Here is a working example that uses several pieces at once:
const log = "2023-06-19 ERROR user=42 path=/login";
// \d digit \w word char \s whitespace
// . any char + 1 or more [] a set of chars
const match = log.match(/(\d{4}-\d{2}-\d{2})\s+(\w+)\s+user=(\d+)/);
console.log(match[1]); // 2023-06-19 (the date group)
console.log(match[2]); // ERROR (the level group)
console.log(match[3]); // 42 (the user id group)Each (...) is a capturing group whose text appears in the result array. \d, \w, and \s are character classes; the quantifiers + and {4} say how many times to repeat the preceding token. Combine these and you can pull structured data out of plain text.
Quick Reference: Flags & Quantifiers
| Category | Symbol/Flag | Description |
|---|---|---|
| Flags | i | Case-insensitive matching |
g | Global match (find all matches) | |
m | Multiline mode (^ and $ match line boundaries) | |
s | Dotall mode (. matches newlines). Requires ES2018+ support. | |
u | Unicode mode | |
y | Sticky mode (matches only from lastIndex) | |
| Quantifiers | * | 0 or more times |
+ | 1 or more times | |
? | 0 or 1 time | |
{n} | Exactly n times | |
{n,} | n or more times | |
{n,m} | Between n and m times |
Common gotchas
A few surprises trip up almost everyone learning regex in JavaScript:
-
A
/gregex remembers where it stopped. When you reuse the sameRegExpobject withtest()orexec(), it advanceslastIndexbetween calls, so the secondtest()can returnfalseon a string that clearly matches. Use a fresh literal each time, or resetre.lastIndex = 0.const re = /a/g; const s = "a"; console.log(re.test(s)); // true console.log(re.test(s)); // false — lastIndex moved past the end -
Dynamic patterns must escape user input. If you build a regex from text the user typed, characters like
.or(are treated as special. Escape them first:const escape = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const userInput = "a.b"; const re = new RegExp(escape(userInput)); console.log(re.test("axb")); // false — the dot is now literal console.log(re.test("a.b")); // true -
Greedy by default.
.+grabs as much as it can; add?to make it lazy (.+?). See Greedy and lazy quantifiers.
Learning roadmap
This page is the gateway to the regex part of the course. Work through the following chapters in order for a complete, hands-on understanding:
- Patterns and flags — constructing patterns and how the flags (
i,g,m,s,u,y) change matching. - Character classes —
\d,\w,\sand their negations. - Unicode: flag
uand class\p{...}— handling multilingual text and emoji. - Anchors: string start
^and end$— matching at boundaries. - Multiline mode of anchors, flag
m— making^and$match each line. - Word boundary
\b— matching whole words. - Escaping special characters — using
.,(,?literally. - Sets and ranges
[...]— custom character sets. - Quantifiers
+,*,?,{n}— specifying repetition. - Greedy and lazy quantifiers — controlling how much is matched.
- Capturing groups — extracting and naming parts of a match.
- Backreferences
\nand\k<name>— reusing captured text. - Alternation (OR)
|— matching one of several options. - Lookahead and lookbehind — zero-width assertions.
- Catastrophic backtracking — diagnosing and avoiding pathological performance.
- Sticky flag
y, searching at position — anchored, position-based matching.
For the methods that run these patterns, see the RegExp object and its methods and the JavaScript strings chapter.
By the end of these lessons, you will be able to craft effective regex patterns for searching, validating, and transforming text in JavaScript.