Developer Guides

Regex for Beginners: 15 Patterns You'll Actually Use

The handful of regex building blocks you need, 15 tested patterns for everyday validation, searching and cleanup, and the mistakes that trip up beginners.

  • By Jacob
  • 6 min read
A magnifying glass over a grid of pale tiles, with a pattern of green and lavender tiles highlighted under the lens

Regular expressions have a reputation for being unreadable, and a long one can be. But most everyday regex work uses the same dozen or so building blocks, and the patterns you actually need are short. This guide covers those building blocks, then 15 patterns for common jobs, each tested against matching and non-matching examples.

All patterns use JavaScript syntax, which is what browsers and Node.js run and what our Regex Tester uses. Most also work unchanged in Python, PHP, Java and other languages, with small differences noted where they matter.

The building blocks

TokenMatches
.Any character except a line break
\d, \w, \sA digit, a word character (letter, digit or underscore), whitespace
\D, \W, \SThe opposite of each: not a digit, not a word character, not whitespace
[abc], [a-z], [^0-9]One character from a set, a range, or anything not in the set
^, $Start and end of the text (or of a line, with the m flag)
\bA word boundary
*, +, ?Zero or more, one or more, zero or one of the previous item
{3}, {2,5}, {2,}Exactly 3, between 2 and 5, 2 or more
(…), (?:…)A capturing group, a group that doesn't capture
a|bEither a or b
\1, $1Whatever group 1 matched (in the pattern, in a replacement)

Flags change how the whole pattern behaves: i ignores case, g finds all matches instead of the first, m makes ^ and $ work per line, and u enables full Unicode support. MDN's regular expressions guide is the best complete reference for the JavaScript flavor.

15 patterns you'll actually use

Validating input

When checking a whole value, wrap the pattern in ^ and $. Without them, the pattern only has to match somewhere in the text, so \d+ happily accepts abc123.

1. Digits only

^\d+$

Matches 0 and 12345. Rejects 12a, 1 2 and an empty string.

2. U.S. ZIP code, with optional ZIP+4

^\d{5}(?:-\d{4})?$

Matches 90210 and 90210-1234. Rejects 9021 and 90210-12.

3. Email address (practical check)

^[^\s@]+@[^\s@]+\.[^\s@]+$

Something without spaces, one @, then a domain with at least one dot. Matches [email protected] and [email protected]. Rejects ann@example, @example.com and ann@@example.com. More on why this is deliberately loose below.

4. U.S. phone number

^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$

Matches (555) 123-4567, 555-123-4567, 555.123.4567 and 5551234567. Rejects 555-1234. For international numbers, it's usually better to strip everything but digits and check the length.

5. Date in YYYY-MM-DD format

^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$

Matches 2026-10-15. Rejects 2026-13-01 and 2026-1-5. Note that it also accepts 2026-02-31: a regex can check the format, but not whether a month has 31 days. Parse the date to check that.

6. 24-hour time

^([01]\d|2[0-3]):[0-5]\d$

Matches 00:00, 09:30 and 23:59. Rejects 24:00, 9:30 and 12:60.

7. Hex color

^#(?:[0-9a-fA-F]{3}){1,2}$

Matches #2B59FF, #2b59ff and the short form #fff. Rejects #2B59F and 2B59FF without the hash.

8. URL slug

^[a-z0-9]+(?:-[a-z0-9]+)*$

Lowercase words joined by single hyphens, like uuid-v4-vs-v7. Rejects capitals, leading or trailing hyphens, and two--dashes. Our Text to Slug tool produces slugs that pass this check.

9. IPv4 address

^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$

Each of the four numbers must be 0–255. Matches 192.168.0.1 and 255.255.255.255. Rejects 256.1.1.1, 1.2.3 and 192.168.01.1 (leading zero). This is a good example of a check that's simpler in code: split on dots and compare numbers.

10. UUID

/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

With the i flag, it matches UUIDs in the standard 8-4-4-4-12 layout, in either case. To tell which version a UUID is, see UUID v4 vs v7.

Finding things in text

Use the g flag to find every match, and drop the ^ and $ anchors. Patterns with flags are shown in JavaScript's /pattern/flags form; in the Regex Tester, type the part between the slashes and tick the flags.

11. Repeated words

/\b(\w+)\s+\1\b/gi

Finds accidental doubles like "the the" or "Is is". (\w+) captures a word, and \1 requires the same word again. Replacing matches with $1 turns This is is a test of the the tool into This is a test of the tool.

12. Hashtags, including accented letters

/#[\p{L}\p{N}_]+/gu

In #launch day! Thanks #team and #café, this finds #launch, #team and #café. \p{L} means any letter in any alphabet, which requires the u flag. A plain #\w+ would stop at the é.

13. Links in plain text

/\bhttps?:\/\/[^\s<>"]+[^\s<>".,;:!?)]/g

Finds https://example.com/a?b=1 and http://test.org in "See https://example.com/a?b=1 and http://test.org." The last character class stops the match from swallowing the sentence's final period.

Cleaning up and rearranging

14. Collapse repeated spaces

/[ ]{2,}/g

Replace each match with a single space. Turns too many spaces into too many spaces. To trim spaces at the start and end instead, replace ^\s+|\s+$ (with g) with nothing.

15. Swap parts with capture groups

Pattern:      ^(\w+),\s*(\w+)$
Replacement:  $2 $1

Pattern:      ^(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})$
Replacement:  $<m>/$<d>/$<y>

The first turns Lovelace, Ada into Ada Lovelace. The second uses named groups to turn 2026-10-15 into 10/15/2026. Named groups make longer patterns much easier to read. You can run replacements like these over a whole document in our Text Replacer, which supports regular expressions and capture groups.

Five mistakes that trip up beginners

1. Forgetting to escape special characters

. matches any character, so example.com also matches exampleXcom. Write example\.com. The same applies to ? + * ( ) [ ] { } ^ $ | \ and, inside JavaScript regex literals, /.

2. Greedy matching

Quantifiers grab as much as they can. On <b>bold</b> and <i>it</i>, the pattern <.+> matches the entire string, from the first < to the last >. Adding ? makes it lazy: <.+?> matches each tag separately. Better still, say what you mean: <[^>]+>.

3. Patterns that take forever

Nested quantifiers like ^(a+)+$ can make the engine try an enormous number of ways to split the input when the match fails. On our test machine, checking 25 a characters followed by ! took almost two seconds, and each extra character roughly doubles the time. This is called catastrophic backtracking, and on a server it can become a denial-of-service problem. Avoid quantifiers inside quantified groups, and test patterns against long inputs that don't match. The Regex Tester stops any match after 2 seconds, so a runaway pattern can't freeze your browser.

4. Trying to validate everything with regex

The full email address grammar in RFC 5322 allows quoted local parts, comments and other rarely used forms, and a regex that follows it exactly is enormous. In practice, use a simple pattern like number 3 to catch typos, then confirm the address by sending an email to it. The same goes for dates, IP addresses and URLs: check the shape with a regex, check the meaning with real parsing.

5. Assuming every language works the same

The basics are portable, but details differ. Named groups are written (?<name>…) in JavaScript but (?P<name>…) in Python's re module, and replacements refer to them differently too. Lookbehind support, Unicode classes like \p{L}, and what \w matches with non-English text all vary between engines. Test patterns in the flavor you'll run them in.

How to build a pattern without getting lost

  1. Collect examples first: several strings that should match and several that shouldn't, including edge cases.
  2. Start small. Match the simplest part, then extend it one piece at a time, checking the examples after each change.
  3. Anchor validation patterns with ^ and $.
  4. Read the explanation back. The Regex Tester breaks a pattern into tokens and explains each in plain English, which catches surprises like an unescaped dot.
  5. Leave a comment in your code saying what the pattern is for and showing one example it matches.

FAQ

What's the difference between * and +?

* allows zero repetitions, + requires at least one. \d* matches an empty string; \d+ doesn't.

Why does my pattern match more than I expected?

Usually because it isn't anchored, a dot isn't escaped, or a quantifier is greedy. Check those three first.

Is regex case-sensitive?

Yes, by default. Add the i flag to ignore case.

Can regex parse HTML?

Not reliably. It's fine for quick searches in known markup, but use an HTML parser for anything real, because nesting, attributes and comments break simple patterns.