← All Articles
Regex

Regex Cheatsheet for Java and JavaScript Developers

Regular expressions are one of those tools that every developer knows they should learn but keeps putting off because the syntax looks impenetrable at first glance. Once you break them down into a small set of composable building blocks, they become an extremely powerful addition to your daily workflow — for validation, parsing log files, search-and-replace operations, and data extraction. This cheatsheet covers the patterns you'll actually use in Java and JavaScript, with real examples.

Character classes

Character classes match a single character from a defined set.

// Literal characters
a          matches the letter "a"
abc        matches the exact string "abc"

// Predefined classes
.          any character except newline
\d         digit [0-9]
\D         non-digit
\w         word character [A-Za-z0-9_]
\W         non-word character
\s         whitespace. Java: exactly [ \t\n\x0B\f\r].
           JS: that set plus the Unicode space separators
           (including NBSP), U+2028, U+2029 and the BOM.
\S         non-whitespace

// Custom classes
[aeiou]    any vowel
[^aeiou]   any non-vowel (^ negates inside [...])
[a-z]      any lowercase letter
[A-Za-z]   any letter
[0-9a-f]   hex digit

In Java strings, backslash must be doubled because it is also Java's escape character: \d in a regex string literal is written as "\\d". In JavaScript, regex literals (/\d/) don't need doubling, but strings passed to new RegExp() do.

Quantifiers

Quantifiers specify how many times the preceding element must match.

*          zero or more (greedy)
+          one or more (greedy)
?          zero or one (optional)
{n}        exactly n times
{n,}       n or more times
{n,m}      between n and m times (inclusive)

// Lazy (non-greedy) — add ? after quantifier
*?         zero or more, as few as possible
+?         one or more, as few as possible

// Example: match HTML tags
// Greedy: <.+>   matches <b>bold</b> as one match (too much)
// Lazy:   <.+?>  matches <b> and </b> separately

Anchors and boundaries

^          start of string (or line in multiline mode)
$          end of string (or line in multiline mode)
\b         word boundary (position between \w and \W)
\B         non-word boundary

// Examples
^Hello      "Hello world" matches, "Say Hello" does not
world$      "Hello world" matches, "worldwide" does not
\bcat\b    matches "cat" but not "catch" or "concatenate"

Groups and capturing

(abc)      capturing group — captures the matched text
(?:abc)    non-capturing group — groups without capturing
(a|b)      alternation — matches "a" or "b"
(?<name>…) named capturing group (Java and JS ES2018+)

// Java example
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2025-06-15");
if (m.find()) {
    String year  = m.group(1);  // "2025"
    String month = m.group(2);  // "06"
    String day   = m.group(3);  // "15"
}

// Named groups in Java
Pattern named = Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
Matcher nm = named.matcher("2025-06-15");
if (nm.find()) {
    String year = nm.group("year");  // "2025"
}

// JavaScript
const match = "2025-06-15".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
const { year, month, day } = match.groups;

Lookahead and lookbehind

Lookarounds assert that a pattern is (or is not) present before or after the current position, without including that context in the match.

(?=…)      positive lookahead — "followed by"
(?!…)      negative lookahead — "not followed by"
(?<=…)     positive lookbehind — "preceded by"
(?<!…)     negative lookbehind — "not preceded by"

// Match a number followed by "px" without including "px"
\d+(?=px)   → from "24px", matches "24"

// Match price preceded by "$"
(?<=\$)\d+  → from "$99", matches "99"

// Password must contain a digit (lookahead validation)
^(?=.*\d).{8,}$   → 8+ chars containing at least one digit

Note: JavaScript supports lookahead in all versions but lookbehind only in ES2018 and later (Node 8.10+, Chrome 62+, Firefox 78+, Safari 16.4+ — Safari was the long straggler here). Java supports both fully.

Common patterns you can use today

Email address (practical, not RFC-perfect)

[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}

// Java — matches() anchors the pattern implicitly, so no ^ or $ needed
Pattern email = Pattern.compile("[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}");

// JavaScript — test() searches anywhere in the string, so anchor it yourself
const emailRegex = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;

The anchors matter more than they look. Java's matches() requires the whole string to match, but JavaScript's test() only looks for the pattern somewhere inside the input — so an unanchored version returns true for " not an email but has x@y.co inside " and for "john@example.com; DROP TABLE". If you use this as a validator, anchor it.

Indian mobile number

^[6-9]\d{9}$

// Allows optional +91 or 0 prefix
^(\+91|0)?[6-9]\d{9}$

// The 6-9 leading digit reflects how mobile numbers are allocated in
// practice. Treat it as a working heuristic, not a published rule.

Date (YYYY-MM-DD)

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

// Matches: 2025-06-15, 2024-12-31
// Rejects: 2025-13-01, 2025-06-32

This checks structure, not the calendar. It accepts 2025-02-30 quite happily, because no regex knows how many days February has. Validate the date itself with LocalDate.parse or an equivalent after the shape check passes.

URL (basic)

https?://[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?

IPv4 address

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

Note the [01]?: this accepts leading zeros, so 192.168.001.1 and 010.1.1.1 both pass. That is worth knowing, because some resolvers read a leading-zero octet as octal — 010 becomes 8 — which is a well-worn way to smuggle an address past an SSRF filter. If you are using this for anything security-relevant, reject leading zeros.

Extract all numbers from a string

// Java
List<String> numbers = new ArrayList<>();
Matcher m = Pattern.compile("\\d+").matcher("Order 42 has 3 items costing 1500");
while (m.find()) numbers.add(m.group()); // ["42", "3", "1500"]

// JavaScript
const numbers = "Order 42 has 3 items costing 1500".match(/\d+/g);
// ["42", "3", "1500"]

Flags / modifiers

// Java flags (combine with |)
Pattern.CASE_INSENSITIVE   // (?i) — case-insensitive matching
Pattern.MULTILINE          // (?m) — ^ and $ match line boundaries
Pattern.DOTALL             // (?s) — dot matches newline too
Pattern.COMMENTS           // (?x) — whitespace and comments ignored

Pattern p = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);

// JavaScript flags (append to literal or pass as string)
/pattern/i    case-insensitive
/pattern/g    global — find all matches
/pattern/m    multiline — ^ and $ match line boundaries
/pattern/s    dotAll — dot matches newline (ES2018+)
/pattern/gi   combined flags

Java String methods that use regex

// Test if entire string matches
"hello123".matches("\\w+")         // true

// Split
"a,b,,c".split(",")                  // ["a", "b", "", "c"]
"a,b,,c".split(",", -1)              // same but keeps trailing empty strings

// Replace first match
"hello world".replaceFirst("\\w+", "hi")  // "hi world"

// Replace all matches
"a1b2c3".replaceAll("\\d", "_")    // "a_b_c_"

// Using named group in replacement
"2025-06-15".replaceAll(
    "(?<y>\\d{4})-(?<m>\\d{2})-(?<d>\\d{2})",
    "${d}/${m}/${y}"
);  // "15/06/2025"

Pitfalls to avoid

Catastrophic backtracking: Patterns like (a+)+ can cause exponential time on certain inputs (ReDoS). Avoid nested quantifiers where the inner and outer patterns can match the same characters. Prefer atomic groups or possessive quantifiers in Java (a++) for performance-critical paths.

Forgetting to escape special characters: The characters . * + ? ^ $ { } [ ] | ( ) \ have special meaning in regex. To match a literal dot, write \.. In Java strings, that's "\\.".

Using regex for HTML/XML parsing: Regex cannot correctly parse nested or malformed HTML. Use a proper parser (Jsoup in Java, DOMParser in the browser) for any non-trivial HTML extraction.

Try it in the browser