Guide · Text, dates and developer tools

Regex Cheat Sheet: Syntax, Flags and Examples You Can Test

In short

A regular expression is a pattern that describes text to find or replace. Letters match themselves, \d matches a digit, [a-z] matches a range, * + and ? repeat, parentheses capture groups, ^ and $ anchor the ends, and flags such as g and i change the search. Test every pattern on real sample text before using it.

What a regular expression is

A regular expression, or regex, is a short pattern that describes a set of strings. You use it to find text (every phone number in a document), to check that text has a certain shape (does this look like a date?), and to change text (swap first and last names). Almost every programming language and many editors support regexes, with a very similar core syntax and a handful of differences, which are covered below.

Most characters match themselves, so cat finds the letters c, a, t in a row. Special characters add power: the pattern ^\d{3}-\d{4}$ reads, part by part, as “^” (the start of the text (the start of each line with the m flag)), “\d” (any digit, 0 to 9), “{3}” (repeat the item before it: exactly 3 times, taking as many as possible (greedy)), “-” (the character "-"), “\d” (any digit, 0 to 9), “{4}” (repeat the item before it: exactly 4 times, taking as many as possible (greedy)), “$” (the end of the text (the end of each line with the m flag)). The regex tester on this site gives a reading like that for any pattern you type.

Regex testerPaste a pattern and some sample text into the regex tester to see every match highlighted, with its groups and position.

The syntax in one table

Characters
PatternMeaning
.any character except a line break
\d \Da digit / not a digit
\w \Wletter, digit or _ / anything else
\s \Swhite space / not white space
[abc] [^abc]one of a, b, c / any but those
[a-z0-9]a range
\p{L}any letter (needs the u flag)
Positions
PatternMeaning
^ $start / end of the text (or line with m)
\b \Ba word edge / not a word edge
(?=x) (?!x)followed by x / not followed by x
(?<=x) (?<!x)preceded by x / not preceded by x
Repeats
PatternMeaning
* + ?0 or more, 1 or more, 0 or 1
{3} {3,} {3,5}exactly 3, 3 or more, 3 to 5
*? +? ??the same, but as few as possible
Groups
PatternMeaning
(x)capture group, numbered from 1
(?:x)group without capturing
(?<name>x)named group
\1 \k<name>the same text again
a|ba or b
In a replacement
PatternMeaning
$1 $2text of group 1, 2
$<name>text of a named group
$&the whole match
$$a dollar sign

To match a character that has a special meaning, put a backslash in front of it: \. is a literal full stop, \( a literal bracket and \\ a literal backslash. The characters that need escaping outside a class are . * + ? ^ $ { } ( ) | [ ] and \. Inside square brackets only ] \ ^ and - usually need it.

Flags change the whole search

  • g (global): find every match instead of stopping at the first.
  • i (ignore case): A matches a as well as A.
  • m (multiline): ^ and $ match at the start and end of every line, not only of the whole text.
  • s (dot all): the dot also matches a line break.
  • u (unicode): read the pattern as Unicode, so an emoji is one character and \p{L} (any letter) works.
  • y (sticky): match only at the exact position where the last match ended.

A common surprise is that without g a replace changes only the first match, and that without m a ^ in a multi-line pasted text matches just once. If a pattern finds fewer things than you expect, check the flags first.

Groups, back-references and replacements

Brackets group part of a pattern and remember what it matched, numbered from 1 by the position of the opening bracket. Naming a group, as in (?<last>\w+), makes the pattern easier to read. A back-reference such as \1 matches the same text again, which is how repeated word detection works: the pattern \b(\w+)\s+\1\b finds “is is” and “the the” in “This is is a test of the the system.”.

In a replacement, $1 is the first group and $<name> is a named one. Using the pattern (?<first>\w+)\s+(?<last>\w+) with the replacement $<last>, $<first> turns “Ada Lovelace” into “Lovelace, Ada”. Use (?:...) when you need grouping for a repeat or an alternative but do not want a numbered capture.

Lookaheads and lookbehinds

Lookarounds check what is next to the match without including it. (?=x) requires x to come next, (?!x) requires that it does not, and (?<=x) and (?<!x) do the same for what comes before. For example \d+(?= dollars) matches the number in “25 dollars” but not the word, and (?<=\$)\d+ matches the digits after a dollar sign. Lookbehinds are the part that differs most between languages, as the next section shows.

Tested patterns for common jobs

Each of these was run on its sample text by the tester on this site and found the matches shown. They are finders, not validators. A pattern can say that text has the shape of an email address, but only sending a message proves the address works.

Example patterns and what they found
JobPatternFound in the sample
Email address/[\w.+-]+@[\w-]+(?:\.[\w-]+)+/gsales@example.com, support+uk@mail.example.co.uk
US phone number/\(?\b\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g(415) 555-0132, 415.555.0188, 4155550199
US ZIP code/\b\d{5}(?:-\d{4})?\b/g94105, 10001-1234
IPv4 address/\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b/g192.168.0.1, 10.0.0.255, 8.8.8.8
Date, yyyy-mm-dd/\b\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])\b/g2026-10-20, 2027-01-05
Time, 24-hour/\b(?:[01]\d|2[0-3]):[0-5]\d\b/g06:30, 14:45, 22:00
Hex colour/#(?:[0-9a-fA-F]{3}){1,2}\b/g#0e6b5a, #fff
Dollar amount/\$\d{1,3}(?:,\d{3})*(?:\.\d{2})?/g$1,250.00, $300, $12.50

The date pattern checks that the month is 01 to 12 and the day 01 to 31, but not that the day exists in that month, so 2026-02-31 still matches. Parsing a date properly is a job for a date library. The same applies to emails, URLs and HTML: use a parser when the input is untrusted and the result matters.

Python, Java, PHP, C# and Go: what changes

The core syntax is shared, which is why a JavaScript pattern often works elsewhere. The differences are where bugs hide.

Where engines differ from JavaScript
FeatureJavaScriptPython (re)JavaPHP (PCRE)C# (.NET)Go (RE2)
Named group(?<n>x)(?P<n>x)(?<n>x)(?<n>x) or (?P<n>x)(?<n>x)(?P<n>x) and (?<n>x) in recent versions
LookaheadYesYesYesYesYesNo
LookbehindAny lengthFixed lengthBounded lengthFixed length (a short range in newer PCRE2)Any lengthNo
Back-referencesYesYesYesYesYesNo
\d matches0 to 9 onlyAny Unicode digit0 to 9 by default0 to 9 by defaultAny Unicode digit0 to 9
\p{L}With the u flagNot in re (use regex)YesWith the u modifierYesYes
$ at the endThe very endAlso before a final line breakAlso before a final line terminatorAlso before a final newlineAlso before a final newlineThe very end by default

Take a pattern that works in JavaScript, such as (?<year>\d{4})-(?<month>\d{2}). In Python it must be written (?P<year>\d{4})-(?P<month>\d{2}). The tester’s Code tab makes that conversion and lists differences it can detect: for this pattern it flags 2 things to check. Go is the odd one out because RE2 guarantees linear-time matching by leaving out lookaround and back-references. That gives it safety from the problem described next, and it also means some patterns simply cannot be written.

These are notes, not a test run The tester runs your pattern on the JavaScript engine only. The tables and notes for other languages come from their documentation. Always run the pattern in the language it is for, with real data, before you rely on it.

When a pattern hangs: catastrophic backtracking

Some patterns take far longer on text that almost matches than on text that matches. The classic is (a+)+$ tried against a long run of a’s followed by an x: the engine tries every way to split the a’s between the inner and outer repeat, and the number of ways doubles with each extra letter. The program seems to hang, and this is the root of ReDoS, where an attacker sends text designed to freeze a server. The tester flags the shape (a repeated group that itself repeats: detected for (a+)+$, not detected for the safe a+$) and runs patterns in a background worker that is stopped after two seconds.

  • Avoid a repeat inside a repeat, such as (x+)+, (x*)* or (\w+\s?)*.
  • Be specific: [^,]* is faster and safer than .* when you mean “everything up to the next comma”.
  • Anchor the pattern with ^ and $ where you can, so it cannot restart at every position.
  • Put a limit on untrusted input, and use an engine such as Go’s RE2 when the pattern itself comes from a user.

Reading the common errors

What the error means
MessageCauseFix
Nothing to repeatA * + ? or {} with nothing in front, often at the startPut something before it, or escape it as \* or \+
Unterminated group / Unmatched )A bracket opened and never closed, or closed too oftenCount the brackets; escape a literal one as \( or \)
Unterminated character classA [ with no ]Add the ], or escape the bracket as \[
Range out of order[z-a] or {5,2}Put the smaller value first
Invalid group(? followed by something unsupported, such as (?P<name> or (?i)Use (?<name>...) and the flag buttons
Invalid escape / property nameA backslash before a letter with the u flag, or a misspelt \p{...}Remove the backslash or fix the property name

Common questions

What does ^ do in a regex?
Outside square brackets, ^ matches the start of the text, or the start of each line with the m flag. Inside square brackets at the start, as in [^abc], it means “any character except these”.
What is the difference between .* and .*? ?
Both match any run of characters. The first is greedy and takes as many as it can; the second, with the question mark, is lazy and takes as few as it can. On <b>one</b><b>two</b> the greedy <b>.*</b> matches the whole string, the lazy one matches each tag pair.
How do I match a literal dot, bracket or dollar sign?
Put a backslash before it: \. for a full stop, \( for a bracket, \$ for a dollar sign. Without the backslash the dot matches any character.
Why does my pattern work in JavaScript but not in Python?
The usual causes are the named group syntax, which is (?P<name>...) in Python, a lookbehind of variable length, which Python does not allow, and \p{...} properties, which Python’s re module does not support.
Can I use a regex to validate an email address?
Only loosely. A regex can reject text that is clearly not an email, but the real rules are far wider than any short pattern, and it cannot tell whether the mailbox exists. Send a confirmation message instead.
Is it safe to paste text into an online regex tester?
It depends on the tool. Some send what you type to a server. This tester runs entirely in your browser and uploads nothing, but avoid pasting secrets such as passwords or keys into any web page on a shared computer.

Sources

Reviewed on 20 Oct 2026 against the published sources below. Laws and prices change, so check the current position before you rely on a figure.

Try the calculator

Keep reading

This guide is general information, not legal, financial or religious advice. Figures are estimates worked out from the sources above and may differ from what applies to you. See the disclaimer. Found a mistake? Tell us.