A regular expression describes a text pattern. Java uses Pattern to compile that pattern and Matcher to apply it to input. Common uses include checking a small identifier, locating repeated tokens, splitting text, and replacing selected matches. The tricky part for beginners is that Java string literals and regular expressions have separate escaping rules. You must first represent the pattern correctly as a Java string, then understand how the regex engine interprets it.
Compile a pattern and create a matcher
Pattern.compile parses the expression once and returns a reusable Pattern. Calling matcher supplies input and creates a Matcher with its own search state. Share a Pattern when the expression is fixed, but create a separate Matcher for each independent operation; Matcher is mutable and not thread-safe. Invalid pattern syntax causes PatternSyntaxException during compilation. For one small check String.matches is convenient, but repeatedly calling it recompiles the pattern rather than reusing a compiled instance.
Distinguish matches from find
Matcher.matches requires the pattern to cover the entire input. Matcher.find searches for the next matching region within the input. A pattern for digits can therefore reject a sentence with matches but locate its numbers with find. After a successful find, group returns the matched text, while start and end identify its bounds. The end position is exclusive, matching the usual substring convention. Repeated find calls advance through the input.
Read character classes and repetition
A character class such as [A-Z] accepts one uppercase ASCII letter. [0-9] accepts one digit, and [^0-9] accepts a character that is not an ASCII digit. Quantifiers describe repetition: + means one or more, * means zero or more, ? means zero or one, and {3} means exactly three. Parentheses group a subexpression and may capture its text. Select the permitted character set deliberately instead of assuming every shorthand matches your domain's rules.
Handle Java string escaping
The regex token \d describes a digit class, but a Java string needs a doubled backslash to preserve that backslash for the regex engine. A literal dot in a regex is escaped because an unescaped dot is a wildcard. For a beginner identifier check, [0-9] and a character class containing a dot can reduce escaping noise. Pattern.quote safely turns an arbitrary search string into literal pattern text instead of interpreting user-supplied punctuation as regex syntax.
Extract capturing groups
Parentheses store parts of a match. In the appointment example, group zero is the entire matched appointment token, group one is its day code, and group two is the hour text. Capturing groups return strings, so convert digits with Integer.parseInt if arithmetic is needed. Noncapturing groups use (?:...) when grouping is needed without an extracted value. Named groups can make a complicated expression easier to maintain than remembering several numeric positions.
Use replacements and validation carefully
replaceAll applies a replacement to every matched region. Replacement strings have their own special treatment of dollar signs and backslashes; Matcher.quoteReplacement protects arbitrary literal replacement text. Regex is useful for constrained text formats, but a matching date-shaped string is not necessarily a valid calendar date. For dates, parse with java.time after checking the representation. Avoid complicated nested repetitions on untrusted long input, because some patterns cause expensive backtracking.
Practice tasks and checks
Change the product-code pattern to permit three uppercase letters followed by two digits. Test one correct code, a lowercase code, an extra trailing character, and a code embedded in a sentence. Use matches for complete validation and find for extraction, then explain why those questions have different answers. Extend the appointment parser with an hour range check after Integer.parseInt so a token such as MON@99 is rejected by domain validation. Finally, replace literal text containing a dollar sign with text containing a backslash. Apply the appropriate quoting method on both sides and confirm the replacement remains literal. This exercise separates Java escaping, pattern interpretation, and replacement interpretation.
Java Summary
- matches validates the whole input; find locates a matching region.
- Java string escaping and regex escaping are separate layers.
- Quote arbitrary pattern and replacement text with their respective APIs.
- Continue with Java strings when these examples are clear.
Java Examples
Each example shows the code, the output it produces and what each part does.
Validate a short product code
Save this program as CodePattern.java. Compile it with javac CodePattern.java and run it with java CodePattern.
Expected output:
The expression accepts exactly two uppercase ASCII letters followed by exactly three digits. QR407 satisfies both parts. The longer sentence fails because matches checks the whole input, not merely the presence of a valid token somewhere inside it. A find call would answer a different question. This code does not verify whether QR407 exists in a product catalog; it checks only the textual format.
import java.util.regex.Pattern;
public class CodePattern {
public static void main(String[] args) {
Pattern code = Pattern.compile("[A-Z]{2}[0-9]{3}");
System.out.println(code.matcher("QR407").matches());
System.out.println(code.matcher("Item QR407").matches());
}
}true
falseFind tokens and read captured parts
Save this program as AppointmentPattern.java. Compile it with javac AppointmentPattern.java and run it with java AppointmentPattern.
Expected output:
Each find locates the next day-and-hour token within the sentence. The first capture contains the three letters and the second contains the two digits; the at sign belongs to the whole match but neither capture. The loop stops when no next match exists. This pattern permits values such as ABC@99, so a real scheduler must validate recognized day codes and valid hour ranges separately.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AppointmentPattern {
public static void main(String[] args) {
Pattern slot = Pattern.compile("([A-Z]{3})@([0-9]{2})");
Matcher matches = slot.matcher("Meet MON@09, then THU@14.");
while (matches.find()) {
System.out.println(matches.group(1) + ": " + matches.group(2));
}
}
}MON: 09
THU: 14Replace literal search text safely
Save this program as LiteralReplacement.java. Compile it with javac LiteralReplacement.java and run it with java LiteralReplacement.
Expected output:
Pattern.quote prevents the plus sign in A+B from acting as a repetition operator. Matcher.quoteReplacement prevents the dollar sign in the replacement from being interpreted as a capture-group reference. The matcher then replaces both literal occurrences. Quoting the pattern and quoting the replacement solve different problems, so applying only one would not fully protect arbitrary text on both sides of the replacement.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LiteralReplacement {
public static void main(String[] args) {
String message = "A+B costs A+B.";
Pattern item = Pattern.compile(Pattern.quote("A+B"));
String result = item.matcher(message)
.replaceAll(Matcher.quoteReplacement("$5"));
System.out.println(result);
}
}$5 costs $5.Java FAQ
Why does a regex need two backslashes in Java?
Java first interprets the string literal. A doubled backslash in that literal becomes one backslash in the runtime string, which the regex engine can then interpret as part of its pattern syntax.
Can regex validate every part of an email address?
A simple expression can check your application's accepted format, but email syntax and deliverability are more complicated. Document the format you support and use confirmation or suitable validation tools when actual mailbox ownership matters.
Should I use String.matches or a compiled Pattern?
text.matches(regex) is convenient for a one-off check, but it compiles the pattern every time it's called. For a pattern used repeatedly, for example inside a loop or a validation method, compile it once into a static final Pattern and reuse it.
How do I make a regex ignore case?
Pass a flag when compiling, Pattern.compile("java", Pattern.CASE_INSENSITIVE), or put (?i) at the start of the expression: "JAVA".matches("(?i)java") is true. By default this applies to ASCII letters; add Pattern.UNICODE_CASE for other alphabets.
What are named groups in Java regex?
A named group gives a captured part a label: (?<year>\d{4})-(?<month>\d{2}). After a successful match, matcher.group("year") returns that part. Names make longer patterns much easier to read than counting parentheses for group(1) and group(2).
Java Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Which Matcher method searches within a longer sentence?
What does group(0) contain?
Java Quiz
2 questions to check what you learned.
Which API makes user search text literal?
- Pattern.quote
- Matcher.quoteReplacement
- Integer.parseInt
Does a match for two hour digits guarantee a valid hour?
- No; numeric range validation is still needed
- Yes; all two-digit numbers are hours
- Only when find is used