In this article
A regular expression, or regex, is a pattern that describes a piece of text. Instead of asking 'is this exactly the word cat?', you ask 'does this look like six digits?' or 'is there a date somewhere in here?'. Almost every programming language and text editor understands the same core ideas.
Anatomy of a pattern
Take the pattern ^[6-9]\d{9}$, a simple check for a 10-digit Indian mobile number. It reads left to right, one piece at a time:
- 1^The match must start at the very beginning of the text.
- 2[6-9]The first character is one of 6, 7, 8 or 9.
- 3\d{9}Followed by exactly nine more digits.
- 4$And then the text must end. Nothing extra is allowed.
Without ^ and $, the pattern would also match inside a longer string such as 1234567890123. Anchors turn 'contains' into 'is exactly'.
The symbols you will use daily
| Symbol | Meaning | Example |
|---|---|---|
\d | One digit, 0 to 9 | \d\d matches 42 |
\w | A letter, digit or underscore | \w+ matches user_1 |
\s | A space, tab or line break | \s+ matches a gap of spaces |
. | Any one character except a new line | c.t matches cat and cot |
[abc] | One of the listed characters | gr[ae]y matches gray and grey |
[^abc] | Any character not listed | [^0-9] matches a non-digit |
+ | One or more | a+ matches a, aa, aaa |
* | Zero or more | ab* matches a, ab, abb |
? | Zero or one (optional) | colou?r matches color and colour |
{n,m} | Between n and m times | \d{2,4} matches 12, 123 and 1234 |
( ) | A group, captured for reuse | (\d+)-(\d+) captures both numbers |
a|b | Either a or b | cat|dog matches either word |
In most languages a backslash inside a normal string has to be doubled, so \d is written \\d in code. In the tester you type it once.
Ten patterns worth keeping
| Goal | Pattern |
|---|---|
| A whole number | ^\d+$ |
| Indian PIN code (6 digits, not starting with 0) | ^[1-9][0-9]{5}$ |
| Indian mobile number | ^[6-9]\d{9}$ |
| A date in the shape 2026-10-09 | ^\d{4}-\d{2}-\d{2}$ |
| A hex colour like #1a2b3c or #abc | ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ |
| A rough email check | ^[^\s@]+@[^\s@]+\.[^\s@]+$ |
| Extra spaces at either end | ^\s+|\s+$ |
| Two or more spaces in a row | \s{2,} |
| Every number inside a paragraph | \d+(\.\d+)? |
| A repeated word such as 'the the' | \b(\w+)\s+\1\b |
The date pattern checks the shape only: it accepts 2026-99-99. The email pattern is a quick sanity check, not full validation. For real validation, confirm by sending a message.
Capture groups: keep the parts you care about
Round brackets mark parts of the match you want to keep. Try (\d{4})-(\d{2})-(\d{2}) on the text 2026-10-09. You get the whole match, plus three groups: 2026, 10 and 09. In JavaScript you can name them with (?<year>\d{4}) and read them back by name, which makes longer patterns far easier to follow.
Groups are numbered by their opening bracket, from left to right.
Greedy or lazy?
Quantifiers like + and * are greedy: they grab as much text as they can and only give some back if the rest of the pattern needs it. That is often not what you want. Take the text <b>one</b> and <b>two</b>:
- Runs to the last </b>
- Swallows everything in between
- Result: <b>one</b> and <b>two</b>
- Stops at the first </b>
- Finds each bold word separately
- Results: <b>one</b> and <b>two</b>
Adding ? after a quantifier makes it lazy. Remember this one: it is behind a huge share of 'my regex matched too much' questions.
Flags change how the whole pattern behaves
Most 'it works on one line but not on my whole text' problems are solved by the m flag.
The trap: catastrophic backtracking
When a regex cannot match, the engine does not give up at once. It tries other ways of splitting the text among the quantifiers. With a pattern such as (a+)+b run against a long line of a's with no b at the end, the number of ways grows by about double with every extra character. A web page that runs such a pattern on user input can freeze its tab, or a server can spend its whole time on one request.
The count is roughly 2 to the power n. Real engines differ in details and some have protections, but you should never depend on that.
A good way to learn
- Start tiny. Match one letter, then add one idea at a time.
- Test on good and bad text. Always include at least one example that should fail.
- Anchor when you validate. Use ^ and $ to check a whole value.
- Prefer simple patterns. If it takes you a minute to read, it will take your teammate longer. Add a comment where you use it.
- Know when not to use regex. For full HTML, JSON or email parsing, use a proper parser.
Questions people ask
What is a regular expression?
A regular expression, or regex, is a pattern that describes a set of strings. You use it to search, check or replace text, for example finding every number in a paragraph or checking that a value looks like a PIN code.
What does \d mean in regex?
\d matches one digit from 0 to 9. \d+ matches one or more digits and \d{6} matches exactly six digits.
What is the difference between greedy and lazy matching?
A greedy quantifier such as .* matches as much as it can. A lazy one such as .*? matches as little as it can. On <b>one</b> and <b>two</b>, <b>.*</b> finds one long match and <b>.*?</b> finds two short ones.
What do ^ and $ do?
^ matches the start of the text and $ matches the end. Using both around a pattern means the whole text must match, not just a part of it.
What is catastrophic backtracking?
It happens when a pattern with nested repeats, such as (a+)+b, fails on a long input and the engine tries an exponential number of ways to split the text. It can make a page or server hang.

