Developer
Regular Expressions for Beginners: A Practical Guide
Learn regular expressions step by step: literals, character classes, quantifiers, groups, anchors and flags, with small examples you can test.
By Vigneshwaran M · 2026-10-03 · 6 min read
A regular expression, often shortened to regex, is a compact pattern that describes a set of strings. You use it to find text, check that input has the right shape, or replace parts of a string. The notation looks cryptic at first, but it is built from a small number of ideas that combine well. You can try every example below in the regex tester.
One caution before starting: regex syntax differs slightly between programming languages and tools. The core is shared, but details such as lookbehind support, named groups and how flags are written can vary. The examples here use the JavaScript flavour, which is also what the tester on this site uses. If you work in another language, check its documentation for differences.
Literal characters and the idea of a match
The simplest pattern is plain text. The pattern cat matches the three characters c, a, t in a row, wherever they appear. In JavaScript you write a pattern between slashes, like /cat/. It would find a match inside "concatenate" as well as in "cat", because the pattern has no idea about word boundaries unless you tell it.
Matching is case-sensitive by default, and the engine reports the first place where the pattern fits, scanning from left to right. Adding the g flag, covered later, makes it keep going to find every match.
Special characters and escaping
A few characters have a special meaning in a pattern: . * + ? ^ $ ( ) [ ] { } | \. To match one of them literally, put a backslash in front. The pattern 3\.5 matches the text 3.5, whereas 3.5 would also match 3x5, because an unescaped dot means "any single character".
The dot is the wildcard. By default it matches any character except a line break.
Character classes
Square brackets define a set, and the pattern matches any one character from it:
[aeiou] one lowercase vowel
[a-z] one lowercase letter
[0-9] one digit
[^0-9] one character that is NOT a digit
A caret at the start inside the brackets negates the set. There are also shorthand classes: \d for a digit, \w for a letter, digit or underscore, and \s for whitespace. Their uppercase forms (\D, \W, \S) mean the opposite.
Quantifiers: how many times
A quantifier says how often the item before it may repeat:
a? zero or one
a* zero or more
a+ one or more
a{3} exactly three
a{2,4} between two and four
So \d{3}-\d{4} matches three digits, a hyphen and four digits, such as 555-0199. The pattern colou?r matches both "color" and "colour", because the u is optional.
Quantifiers are greedy by default: they take as much text as they can while still letting the whole pattern succeed. Add a question mark after the quantifier to make it lazy, which takes as little as possible. Take the text <b>one</b> and <b>two</b> as an example. The greedy pattern <b>.*</b> grabs everything from the first opening tag to the last closing tag, while the lazy <b>.*?</b> stops at the first closing tag and finds each piece separately.
Anchors and boundaries
Anchors do not consume characters; they assert a position:
^is the start of the text, and$is the end.\bis a word boundary, the position between a word character and a non-word character.
Anchors are how you turn "contains" into "is exactly". The pattern \d+ is found inside "abc123", but ^\d+$ only matches a string made entirely of digits. Likewise \bcat\b finds the word "cat" but ignores "concatenate".
Groups, alternation and capturing
Parentheses group part of a pattern so that a quantifier can apply to the whole group, and they also capture the matched text so you can reuse it. The vertical bar means "or":
const date = /(\d{4})-(\d{2})-(\d{2})/;
const m = "Due 2026-10-03".match(date);
// m[0] is "2026-10-03", m[1] is "2026", m[2] is "10", m[3] is "03"
Each pair of parentheses becomes a numbered capture. Modern JavaScript also supports named groups written like (?<year>\d{4}), which makes the result easier to read. If you need a group only for structure and do not want to capture it, write (?:...).
Alternation reads as: cat|dog matches either word. When you combine it with other text, wrap it in a group, for example gr(a|e)y for both spellings of the colour.
Flags
Flags change how the whole pattern behaves. They are written after the closing slash:
gfinds all matches instead of stopping at the first.iignores case, so/cat/imatches "Cat" and "CAT".mmakes^and$work on each line instead of the whole text.slets the dot match line breaks as well.
Flags can be combined, for example /error/gi.
A worked example
Suppose you want to pull out hexadecimal colour codes such as #1a2b3c from a block of text. Build the pattern in small steps:
- A literal
#. - Then six characters from the set
[0-9a-fA-F]. - Add
\bat the end so it does not stop in the middle of a longer run of characters.
const hex = /#[0-9a-fA-F]{6}\b/g;
"bg #1a2b3c, text #FFFFFF".match(hex);
// ["#1a2b3c", "#FFFFFF"]
Building a pattern one piece at a time, and testing after each piece, is the most reliable way to avoid confusing patterns.
Common mistakes
- Forgetting to escape special characters. A dot, plus sign or parenthesis that you mean literally needs a backslash.
- Using greedy matching by accident. If a pattern swallows more text than expected, try the lazy form of the quantifier or a more specific character class.
- Missing anchors. Validation patterns usually need
^and$; without them, a match anywhere in the text counts. - Over-trusting a regex for complex formats. Patterns for things like email addresses or full HTML documents get long and still miss cases. Use a regex for simple, well-defined shapes, and a proper parser or library for nested or intricate formats.
- Nested repetition. A pattern such as a group with a quantifier inside another quantifier can make some engines take a very long time on certain inputs, a problem known as catastrophic backtracking. Keep repeated parts simple, and be careful when running user-supplied patterns.
- Assuming the pattern works the same everywhere. Test in the environment you will deploy to.
Quick checklist
- Start with the simplest literal pattern and grow it.
- Escape characters that have special meaning when you want them literally.
- Choose between
*,+,?and{n,m}deliberately. - Add anchors for validation and
\bfor whole words. - Decide whether you need
g,iorm. - Test with both matching and non-matching examples.
Related tools
The regex tester lets you type a pattern, set flags and see matches highlighted instantly, which is the quickest way to learn by experiment. To count or inspect the text you are searching, the word counter is handy, and when your pattern is meant to pull values out of structured data, the JSON formatter can help you view the source clearly first.