Java Regular Expressions — Pattern, Matcher & Common Patterns

3 minute read

Regular expressions (regex) let you describe patterns in text. Java’s java.util.regex package provides Pattern and Matcher for powerful, reusable pattern matching.


Quick Start

String email = "alice@example.com";
boolean valid = email.matches("[\\w.+-]+@[\\w-]+\\.[a-zA-Z]{2,}");
System.out.println(valid);  // true

Core Classes

Pattern — Compiled Regex

import java.util.regex.Pattern;
import java.util.regex.Matcher;

Pattern pattern = Pattern.compile("\\d+");  // one or more digits

Compile once, reuse many times — much faster than calling String.matches() repeatedly.

Matcher — Applying a Pattern

Matcher matcher = pattern.matcher("Order 42, Item 7");

while (matcher.find()) {
    System.out.println("Found: " + matcher.group());
}
// Found: 42
// Found: 7

Regex Syntax Reference

Character Classes

Pattern Matches
. Any character (except newline)
\d Digit [0-9]
\D Non-digit
\w Word character [a-zA-Z0-9_]
\W Non-word character
\s Whitespace [ \t\n\r\f]
\S Non-whitespace
[abc] a, b, or c
[^abc] Not a, b, or c
[a-z] Lowercase letter

Quantifiers

Quantifier Meaning
* 0 or more
+ 1 or more
? 0 or 1 (optional)
{n} Exactly n
{n,} n or more
{n,m} Between n and m

Anchors

Anchor Meaning
^ Start of string
$ End of string
\b Word boundary

String Regex Methods

String s = "Hello 123 World 456";

// matches() — must match ENTIRE string
s.matches(".*\\d+.*")              // true

// replaceAll() — replace all matches
s.replaceAll("\\d+", "#")          // "Hello # World #"

// replaceFirst() — replace first match
s.replaceFirst("\\d+", "#")        // "Hello # World 456"

// split() — split by regex
"one:two::three".split(":")        // ["one", "two", "", "three"]
"one:two::three".split(":+")       // ["one", "two", "three"]

Groups and Capturing

Parentheses create capturing groups:

Pattern p = Pattern.compile("(\\w+)@(\\w+)\\.(\\w+)");
Matcher m = p.matcher("alice@example.com");

if (m.matches()) {
    System.out.println("Full:   " + m.group(0));  // alice@example.com
    System.out.println("User:   " + m.group(1));  // alice
    System.out.println("Domain: " + m.group(2));  // example
    System.out.println("TLD:    " + m.group(3));  // com
}

Named Groups (Java 7+)

Pattern p = Pattern.compile("(?<user>\\w+)@(?<domain>\\w+\\.\\w+)");
Matcher m = p.matcher("alice@example.com");

if (m.matches()) {
    System.out.println(m.group("user"));   // alice
    System.out.println(m.group("domain")); // example.com
}

Common Patterns

Email (Basic)

String emailRegex = "[\\w.+-]+@[\\w-]+\\.[a-zA-Z]{2,}";

Phone Number (US)

String phoneRegex = "\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}";
// Matches: (123) 456-7890, 123-456-7890, 123.456.7890

URL

String urlRegex = "https?://[\\w.-]+(?:/[\\w./-]*)?";

IP Address (IPv4)

String ipRegex = "\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b";

Date (YYYY-MM-DD)

String dateRegex = "\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])";

Practical Examples

Extract All URLs from Text

String text = "Visit https://example.com or http://docs.java.net/api for info.";
Pattern p = Pattern.compile("https?://[\\w.-]+(?:/[\\w./-]*)?");
Matcher m = p.matcher(text);

while (m.find()) {
    System.out.println(m.group());
}
// https://example.com
// http://docs.java.net/api

Validate and Parse CSV Line

String line = "Alice,30,\"New York\"";
Pattern p = Pattern.compile("\"([^\"]*)\"|([^,]+)");
Matcher m = p.matcher(line);

while (m.find()) {
    String value = m.group(1) != null ? m.group(1) : m.group(2);
    System.out.println(value);
}
// Alice
// 30
// New York

Word Frequency Counter

String text = "the cat sat on the mat the cat";
Pattern word = Pattern.compile("\\b\\w+\\b");
Matcher m = word.matcher(text.toLowerCase());

Map<String, Integer> freq = new HashMap<>();
while (m.find()) {
    freq.merge(m.group(), 1, Integer::sum);
}
System.out.println(freq);
// {the=3, cat=2, sat=1, on=1, mat=1}

Flags

// Case-insensitive
Pattern p = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);

// Multiple flags
Pattern p2 = Pattern.compile("^start", 
    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

// Inline flag
Pattern p3 = Pattern.compile("(?i)hello");
Flag Constant Inline
Case-insensitive CASE_INSENSITIVE (?i)
Multiline MULTILINE (?m)
Dotall (. matches \n) DOTALL (?s)
Comments COMMENTS (?x)

Performance Tips

  1. Compile once, reuse — Pattern.compile() is expensive. Store the Pattern as a static final field.
  2. Avoid catastrophic backtracking — be careful with nested quantifiers like (a+)+.
  3. Use possessive quantifiers (++, *+) or atomic groups when possible.
  4. Prefer String methods for simple tasks — don’t use regex for contains() or startsWith().
// GOOD — compiled once
private static final Pattern DIGITS = Pattern.compile("\\d+");

public List<String> findNumbers(String text) {
    Matcher m = DIGITS.matcher(text);
    List<String> results = new ArrayList<>();
    while (m.find()) results.add(m.group());
    return results;
}

Common Mistakes

Mistake Problem Fix
"\\d" vs "\d" Java strings need double backslash Always \\d in Java
matches() expects full match "123abc".matches("\\d+") → false Use find() for partial match
Not reusing Pattern Recompiles every call Store as static final
Greedy by default .* grabs too much Use .*? for lazy

Key Takeaways

  1. Use Pattern.compile() + Matcher for reusable, performant regex.
  2. String.matches() checks the entire string; Matcher.find() finds partial matches.
  3. Use named groups for readable extraction.
  4. Compile patterns once and store as static final.
  5. Don’t use regex when simple String methods suffice.

What’s Next?

We move into utility classes, starting with Java Enum — type-safe constants with fields, methods, and more.

Updated: