Development
Regex Cheat Sheet: Regular Expressions Reference for Developers
A complete regular expressions cheat sheet covering character classes, anchors, quantifiers, groups, lookaheads, and common regex patterns for JavaScript, Python, and PHP. Includes working examples for email, URL, date, and IP address validation.
What Are Regular Expressions?
A regular expression (regex or regexp) is a sequence of characters that defines a search pattern. Regex patterns are used to search, match, validate, extract, and replace text. They are supported in virtually every programming language — JavaScript, Python, PHP, Java, Go, Ruby, Rust — and in many text editors, command-line tools like grep and sed, and databases.
Regex is one of the most efficient tools for text processing tasks that would otherwise require many lines of string manipulation code. A single regex pattern can validate an email address, extract all URLs from an HTML document, or find all lines in a log file that contain a specific HTTP status code. The same pattern works consistently across millions of lines of text in milliseconds.
The syntax for regular expressions is largely consistent across programming languages, with minor differences in features and how patterns are delimited. JavaScript wraps regex patterns in forward slashes: /pattern/flags. Python uses the re module with strings: re.search(r'pattern', text). The core syntax — character classes, anchors, quantifiers, groups — works the same way in all major languages.
Literal Characters and Character Classes
Literal characters in a regex match themselves exactly. The pattern hello matches the string hello anywhere in the input. Most letters and digits are literal characters. Special characters with regex meaning — . * + ? ^ $ { } [ ] ( ) | — must be escaped with a backslash when you want to match them literally: \. matches a period, \$ matches a dollar sign.
A character class is a set of characters enclosed in square brackets. [abc] matches any single character that is a, b, or c. [0-9] matches any digit. [a-zA-Z] matches any ASCII letter. A caret inside the brackets negates the class: [^0-9] matches any character that is not a digit. Character classes can contain both literal characters and ranges.
The dot (.) is a special character that matches any single character except a newline by default. It is the most commonly misused character in regex — when you want to match a literal period, always escape it as \. rather than using the bare dot, which matches any character. In JavaScript, the s (dotAll) flag makes the dot also match newlines.
- [abc] — matches a, b, or c
- [a-z] — matches any lowercase letter
- [A-Z] — matches any uppercase letter
- [0-9] — matches any digit
- [^abc] — matches any character except a, b, c
- [a-zA-Z0-9] — matches any alphanumeric character
- . — matches any character except newline (use \. to match a literal period)
Anchors: ^ and $
Anchors do not match characters — they match positions in the string. The caret (^) matches the beginning of the string (or the beginning of a line in multiline mode). The dollar sign ($) matches the end of the string (or the end of a line in multiline mode). Without anchors, a pattern can match anywhere inside the string.
The pattern hello matches the word hello anywhere in the string: it matches in hello world and in say hello and in ohello. Adding anchors changes the behavior: ^hello matches hello only at the start, hello$ matches hello only at the end, and ^hello$ matches only the string that is exactly hello with nothing else.
\b is a word boundary anchor that matches the position between a word character (letter, digit, or underscore) and a non-word character. It is useful for matching whole words: \bcat\b matches cat as a word but not catfish or tomcat. Word boundaries are particularly useful for searching logs, code, and documents where you want exact word matches without splitting words.
Quantifiers: *, +, ?, and {n,m}
Quantifiers specify how many times the preceding element must occur. The asterisk (*) means zero or more times. The plus sign (+) means one or more times. The question mark (?) means zero or one time (making the element optional). These are greedy by default — they match as many characters as possible.
The curly-brace quantifiers give precise control: {n} matches exactly n times, {n,} matches n or more times, {n,m} matches between n and m times inclusive. For example, [0-9]{3} matches exactly three consecutive digits. [a-z]{2,5} matches a lowercase word between 2 and 5 characters long.
Greedy quantifiers match as much as possible and then backtrack. This can cause unexpected behavior when the pattern has multiple matches. Adding a question mark after a quantifier makes it lazy (non-greedy), matching as little as possible: .*? instead of .*. For example, the greedy <.*> applied to <b>hello</b> matches the entire string from the first < to the last >. The lazy <.*?> matches only <b> (the shortest possible match).
- * — zero or more (greedy)
- + — one or more (greedy)
- ? — zero or one (optional)
- {3} — exactly 3 times
- {2,5} — between 2 and 5 times
- {3,} — 3 or more times
- *? or +? or {n,m}? — lazy (non-greedy) version
Shorthand Character Classes: \d, \w, \s
Regex provides shorthand character classes for commonly used sets. \d matches any digit, equivalent to [0-9]. \w matches any word character — letters, digits, and underscore — equivalent to [a-zA-Z0-9_]. \s matches any whitespace character — space, tab, newline, carriage return, form feed.
The uppercase versions are negations: \D matches any non-digit (equivalent to [^0-9]). \W matches any non-word character. \S matches any non-whitespace character. These are concise and readable alternatives to explicit character classes.
In Unicode-aware regex engines (JavaScript with the u flag, Python 3 with re.UNICODE which is the default), \d may match Unicode digits beyond 0-9, \w may match Unicode word characters, and \s may match Unicode whitespace. This is usually desirable for internationalized text processing but can cause surprises if you expect ASCII-only matching. Specify [0-9] instead of \d if you need to restrict to ASCII digits only.
Groups and Alternation
Parentheses create a capturing group. The pattern (\d{4})-(\d{2})-(\d{2}) matches a date in YYYY-MM-DD format and captures the year, month, and day in three separate groups. In JavaScript, match[1] returns the year, match[2] the month, match[3] the day. Capturing groups also allow backreferences: \1 refers back to what the first group matched.
Non-capturing groups use the syntax (?:...) — they group characters for quantifier application or alternation without capturing the match. Use non-capturing groups when you need grouping but do not need to extract the matched content, as they are slightly faster and keep the match array smaller.
The pipe character (|) is the alternation operator, matching the expression on either side: cat|dog matches either cat or dog. Alternation has the lowest precedence in regex — (cat|dog)s matches cats or dogs, while cats|dogs matches cats or dogs (same result here but the grouping becomes important in more complex patterns). Always use explicit groups around alternation when the scope might be ambiguous.
Lookaheads and Lookbehinds
Lookaheads match a position where the pattern is followed by (or not followed by) another pattern, without including the following pattern in the match. A positive lookahead uses the syntax (?=...): \d+(?= dollars) matches a number only if it is followed by the word dollars, but the matched text does not include dollars. A negative lookahead uses (?!...): \d+(?! dollars) matches a number only if it is not followed by dollars.
Lookbehinds work in the opposite direction — they match a position based on what comes before. A positive lookbehind uses (?<=...): (?<=\$)\d+ matches digits only when preceded by a dollar sign, without including the dollar sign in the match. A negative lookbehind uses (?<!...): (?<!\$)\d+ matches digits not preceded by a dollar sign.
Lookaheads and lookbehinds are zero-width assertions — they match a position, not characters, so they do not consume characters from the input. They are powerful for extracting or replacing content that appears in a specific context without altering the surrounding text. Not all regex engines support lookbehinds (older JavaScript before ES2018 did not), so check compatibility before using them in production code.
Common Regex Patterns for Developers
Email validation (simplified): /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/. This covers the most common email formats. A fully RFC 5322-compliant email regex is hundreds of characters long and often impractical. The simplified version catches the vast majority of invalid inputs.
URL matching: /https?:\/\/[^\s]+/g. This matches http or https followed by :// and any non-whitespace characters. It is intentionally simple and will match URLs in text without trying to validate the full URL structure. For stricter URL validation, use the URL constructor in JavaScript (new URL(str)) rather than a regex.
IPv4 address: /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/. This validates that each octet is between 0 and 255. ISO date (YYYY-MM-DD): /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/. Hex color: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.
Regex Flags: g, i, m, s, u
Regex flags modify the behavior of the pattern matching. The most commonly used flags: g (global) finds all matches rather than stopping at the first match. i (case-insensitive) matches letters regardless of case. m (multiline) makes ^ and $ match the start and end of each line rather than the start and end of the entire string.
s (dotAll) makes the dot (.) match any character including newlines. This flag is available in JavaScript (ES2018+), Python (re.DOTALL), and most modern regex engines. Without the s flag, a dot in a pattern does not match a newline character, which can cause patterns to fail when the input spans multiple lines.
u (unicode) enables full Unicode matching in JavaScript. When using the u flag, \d, \w, and character ranges behave correctly with Unicode code points, and the pattern syntax is stricter (some sequences that were silently ignored become syntax errors). Always use the u flag in JavaScript when working with text that may contain non-ASCII characters.
Common Regex Mistakes and How to Avoid Them
Using . when you mean a literal period. The dot matches any character, so [a-z]+.[a-z]+ matches any string with two groups of letters and any single character between them, not necessarily a period. Always escape it as \. when matching a literal period.
Catastrophic backtracking: patterns like (a+)+ applied to a long string of non-matching characters can cause the regex engine to take exponential time testing all possible ways the pattern could match. This is a real denial-of-service vulnerability in web applications. Avoid nested quantifiers and write patterns that fail fast on non-matching input.
Anchoring failures: forgetting to add ^ and $ when validating a complete string means the pattern matches anywhere in the string. The pattern \d{4} without anchors matches a 4-digit number anywhere in 1234567, including the first 4 digits, which might not be what you intend. Add ^ at the start and $ at the end when you want the pattern to match the entire string.
FAQ
What does * mean in regex?
In regex, * is a quantifier that means zero or more occurrences of the preceding element. a* matches zero or more a characters: it matches an empty string, a, aa, aaa, and so on. Combined with ., the pattern .* matches zero or more of any character — effectively any string of any length. The * is greedy by default, matching as many characters as possible. To make it lazy (match as few as possible), use *?.
How do I match a literal special character in regex?
Escape the character with a backslash. The special characters that need escaping are: . * + ? ^ $ { } [ ] ( ) | \. To match a period, use \.. To match a dollar sign, use \$. To match a backslash itself, use \\. In JavaScript string literals, you need to double the backslash because the string itself also uses \ as an escape character, so a regex backslash-period becomes the string \\. (four characters in the source code).
What is the difference between . and \w in regex?
The dot (.) matches any single character except a newline (and matches newlines too when the s flag is used). \w matches only word characters: letters (a-z, A-Z), digits (0-9), and underscore (_). The dot is broader — it matches punctuation, spaces, and special characters that \w does not. Use \w when you want to match alphanumeric characters and underscores specifically. Use . when you want to match almost anything.
What does \b mean in regex?
\b is a word boundary anchor. It matches the position between a word character (letter, digit, or underscore) and a non-word character (space, punctuation, start/end of string). It does not match any character itself — it matches a position. \bword\b matches word as an isolated word but not as part of keyword or wording. Word boundaries are useful for finding whole-word matches in text.
How do I make a regex case-insensitive?
Add the i flag to your regex. In JavaScript: /hello/i matches Hello, hello, HELLO, and all other capitalizations. In Python: re.search(r'hello', text, re.IGNORECASE) or use the (?i) inline flag: re.search(r'(?i)hello', text). In grep: use the -i flag. The case-insensitive flag applies to all letter matching in the pattern, including character classes and ranges.
What is a capturing group in regex?
A capturing group is a part of the pattern enclosed in parentheses. It does two things: it groups the enclosed pattern so quantifiers and alternation apply to the whole group, and it captures (records) what that group matched. You can then access the captured text in your code. In JavaScript, the match() or exec() return value includes the full match at index 0, followed by each capturing group in order. Non-capturing groups (?:...) group without capturing.
What is the difference between greedy and lazy quantifiers?
Greedy quantifiers (*, +, {n,m}) match as many characters as possible and then backtrack if needed. Lazy quantifiers (*?, +?, {n,m}?) match as few characters as possible and expand if needed. With <.*> applied to <b>hello</b>world</b>, greedy matches the entire <b>hello</b>world</b> string. Lazy <.*?> matches only <b>. Use lazy quantifiers when you want the shortest possible match, such as when extracting tags or delimited values from text.
How do I test a regex pattern?
Use the regex tester tool on this site to test patterns against sample text in real time. You can also test in your browser console using JavaScript: /pattern/flags.test('string') returns true or false, and 'string'.match(/pattern/flags) returns the matched content. In Python, use re.findall(r'pattern', text) to see all matches. Online tools like regex101.com provide detailed explanations of what each part of a pattern matches.
Can regex match across multiple lines?
By default, the dot (.) does not match newlines, so patterns that use .* or .+ do not cross line boundaries. To match across multiple lines, use the s (dotAll) flag: in JavaScript /pattern/s, in Python re.DOTALL. The m (multiline) flag changes ^ and $ to match line starts and ends rather than string starts and ends — it does not make . match newlines. You often need both m and s together for multi-line content matching.
Is regex the right tool for parsing HTML or XML?
Generally no. HTML and XML are nested, recursive structures that cannot be described by regular languages. A regex that extracts content from one valid HTML document will often break on another. For robust HTML parsing, use a purpose-built HTML parser: DOMParser in browsers, cheerio or htmlparser2 in Node.js, BeautifulSoup in Python, or DOMDocument in PHP. Use regex only for extracting simple patterns from HTML when a full parser would be overkill.
Related free tools
If you want to turn this topic into action, use one of ShortIQ's free tools for campaign planning, UTM structure, or QR distribution.
Continue Reading
Explore more guides on link shortener SaaS strategy, Bitly alternatives, and white label link management.
Free newsletter
Get new guides in your inbox
We publish practical guides on dev tooling, prompt engineering, marketing workflows, and deployment. No fluff — straight to the point.
No spam. Unsubscribe any time.
Was this article helpful?
Tell us if this guide solved the problem or what was still missing. We use this to improve the blog and only follow up if you explicitly allow it.