🧰 Core APIs Toolbox · Intermediate

Regular expressions in Java

Pattern, Matcher, groups, matches vs find, common regex pitfalls.

🧩 The mystery"a.b.c".split(".") — three parts, obviously? Java says the array has length 0. The dot is not what it seems…

A pattern for text

A regex describes text shapes: **\d a digit, \w a word character, + one or more, . *any* character. Compile once with Pattern.compile, then create a Matcher for each text. In Java strings the backslash is doubled: "\\d"**.

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("order 66");

matches vs find

**matches() succeeds only if the entire input** fits the pattern (String.matches too). **find() searches for the next match anywhere** in the text.

🔮 Predict it

Whole or part?

What does this print?

String s = "abc123";
System.out.println(s.matches("[a-z]+"));
System.out.println(Pattern.compile("[a-z]+")
    .matcher(s).find());
  1. true true
  2. false true
  3. false false
Show the answer

false — "abc123" isn't made *only* of letters. true — find spots "abc" inside it.

Groups capture pieces

Parentheses create groups, numbered by their opening parenthesis, left to right. **group(0)** is the whole match, group(1) the first ( ), and so on.

var p = Pattern.compile("(\\d{4})-(\\d{2})");
var m = p.matcher("Due 2024-07");
if (m.find()) {
    m.group(1); // "2024"
    m.group(2); // "07"
}
🔮 Predict it

Which group?

What does this print?

var p = Pattern.compile("(\\d+)-(\\d+)");
var m = p.matcher("call 555-1234 now");
if (m.find()) {
    System.out.println(m.group(2));
}
  1. 555
  2. 1234
  3. 555-1234
Show the answer

1234 — group 1 is "555", group 2 is "1234", and group 0 would be the whole "555-1234".

⚠️ The trap

Greedy stars

.* is greedy: it grabs as much as possible, from the first < to the last > — swallowing "hi" too, so this prints an empty line. Use reluctant **<.*?> or <[^>]+>** to match one tag at a time.

String html = "<b>hi</b>";
html.replaceAll("<.*>", "");   // ""
html.replaceAll("<[^>]+>", ""); // "hi"

Splitting on a dot

✗ Regex surprise
"a.b.c".split(".").length // 0

. matches any character, so every char is a separator; the pieces are all empty and trailing empties are removed.

✓ Escaped dot
"a.b.c".split("\\.") // [a, b, c]

\\. in Java source means the regex \.: a literal dot.

💼 In the real world

Regex on the job

Validating input, parsing log lines, extracting IDs from URLs — regex is everywhere. Teams compile patterns once into static final Pattern constants (compiling is costly) and treat greedy .* and unescaped dots as code-review red flags.

Key takeaways

  1. matches(): whole string; find(): any part of it
  2. group(0) is the whole match; group(1) the first ( )
  3. In Java strings, \d must be written "\\d"
  4. split(".") is a regex: escape it as "\\."
🤯 Did you know?

Regular expressions were invented in the 1950s by mathematician Stephen Kleene — the * operator is still called the "Kleene star".

Practice questions

What does this print?

String s = "order 66";
System.out.println(s.matches("\\d+"));
System.out.println(
    Pattern.compile("\\d+").matcher(s).find());
  1. true true
  2. false true
  3. true false
  4. false false
Check your answer

false true. "order 66" is not made entirely of digits, so matches is false. find succeeds because "66" appears inside it.

What does this print?

Pattern p = Pattern.compile("(\\w+)@(\\w+)\\.com");
Matcher m = p.matcher("mail ana@site.com now");
if (m.find()) {
    System.out.println(m.group(2));
}
  1. ana
  2. site
  3. ana@site.com
  4. com
Check your answer

site. Groups are numbered by their opening parenthesis from left to right: group(1) is "ana", group(2) is "site". group(0) is the whole match.

Next: the humble Objects class — a toolbox that makes null far less scary.