Regular Expressions in Java (Regex) - Quiz
Total: 6 questions
1. How do you use a regular expression in Java with the Pattern and Matcher classes?
How do you use a regular expression in Java with the Pattern and Matcher classes?
Compile the pattern with Pattern.compile(regex), then call pattern.matcher(text) to get a Matcher for a particular string. Neither class has a public constructor. A syntax error in the pattern is detected at compile time and throws PatternSyntaxException.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DigitsFinder {
private static final Pattern DIGITS = Pattern.compile("\\d+");
public static void main(String[] args) {
Matcher m = DIGITS.matcher("a1b22");
while (m.find()) {
System.out.println(m.group() + " [" + m.start() + ", " + m.end() + ")");
}
}
}
// Output:
// 1 [1, 2)
// 22 [3, 5)
Pattern is immutable and thread-safe, so you create it once (for example, in a static final field) and reuse it. Matcher keeps the search state — the current position, the last match and its groups — and is not thread-safe: for a new string, create a new Matcher or call reset(text). The check itself is done by one of three methods: matches() — the pattern matches the whole string, lookingAt() — its beginning, find() — looks for the next match anywhere. The String.matches(), split() and replaceAll() methods recompile the pattern on every call.
2. What are regex metacharacters, and why is the backslash doubled in a Java string?
What are regex metacharacters, and why is the backslash doubled in a Java string?
Metacharacters are characters with a special meaning in a pattern: . ^ $ | ( ) [ ] { } \ ? * +. All other characters match themselves. To match a metacharacter literally, put a backslash in front of it (\., \$, \(), place it inside a set ([.]) or pass the string through Pattern.quote().
The backslash is also the escape character of Java string literals, so the pattern \d is written in code as "\\d", and \. as "\\.". Writing "\d" does not compile (illegal escape character), and to match a literal backslash in the text, a Java string needs four of them: "\\\\". Java has no raw strings, and text blocks (Java 15) process escape sequences too.
System.out.println("java".matches("j.va")); // true: the dot is any character
System.out.println("java".matches("j\\.va")); // false: \. is the dot itself
System.out.println("j.va".matches("j\\.va")); // true
System.out.println("C:\\dir".replaceAll("\\\\", "/")); // C:/dir
3. What character classes are there in Java regex: \d, \s, \w and [ ] sets?
What character classes are there in Java regex: \d, \s, \w and [ ] sets?
A character class matches exactly one character from a set. Sets in square brackets: [abc] — one of the listed characters, [a-c] — a range, [^abc] — any character except the listed ones. Ready-made shortcuts: \d — a digit ([0-9]), \s — a whitespace character (space, \t, \n, \r, \f, \x0B), \w — a word character ([a-zA-Z_0-9]). The uppercase \D, \S, \W are their negations. \b is a word boundary (a position, not a character), \p{L} is any Unicode letter.
System.out.println("a1 b2".replaceAll("[^a-z]", "")); // ab
System.out.println("Café".matches("\\w+")); // false
System.out.println("Café".matches("\\p{L}+")); // true
By default, \w and \b know only ASCII, and the range [a-z] does not include é or ü. For text in any language, use \p{L} or the UNICODE_CHARACTER_CLASS flag.
4. What quantifiers does Java regex have, and how is a greedy quantifier different from a lazy one?
What quantifiers does Java regex have, and how is a greedy quantifier different from a lazy one?
A quantifier sets how many times the preceding element (a character, a class or a group) repeats: ? — 0 or 1 time, * — 0 or more, + — 1 or more, {n} — exactly n, {n,} — n or more, {n,m} — from n to m inclusive. For example, colou?r matches color and colour, and \d{2,4} matches 12 and 2026, but not the whole string 20261.
By default, quantifiers are greedy: they take as much text as possible and back off only on failure. With an extra ? (*?, +?, {n,m}?) they become lazy and take as little as possible. With an extra + (*+, ++) they become possessive: greedy, but without backtracking.
Matcher greedy = Pattern.compile("'.*'").matcher("'a' and 'b'");
greedy.find();
System.out.println(greedy.group()); // 'a' and 'b'
Matcher lazy = Pattern.compile("'.*?'").matcher("'a' and 'b'");
lazy.find();
System.out.println(lazy.group()); // 'a'
A negated set '[^']*' gives the same result as the lazy version and is faster, because it does no backtracking.
5. How do you enable case-insensitive matching and other Pattern flags in Java regex?
How do you enable case-insensitive matching and other Pattern flags in Java regex?
Pass flags as the second argument of Pattern.compile(regex, flags), combined with |, or switch them on inside the pattern with an embedded flag such as (?i). The main flags: CASE_INSENSITIVE ((?i)) — case-insensitive matching; UNICODE_CASE ((?u)) — case folding by Unicode rules; MULTILINE ((?m)) — ^ and $ match on every line of the text; DOTALL ((?s)) — the dot also matches line terminators; UNICODE_CHARACTER_CLASS ((?U)) — \w, \d, \b follow Unicode; LITERAL — the whole pattern is treated as plain text.
System.out.println(Pattern.compile("café", Pattern.CASE_INSENSITIVE)
.matcher("CAFÉ").matches()); // false
System.out.println(Pattern.compile("café", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)
.matcher("CAFÉ").matches()); // true
System.out.println("JAVA".matches("(?i)java")); // true
System.out.println(Pattern.compile("^\\w+$", Pattern.MULTILINE)
.matcher("one\ntwo").results().count()); // 2
The tricky part: CASE_INSENSITIVE on its own folds case only for ASCII letters, so é and É stay different characters until you add UNICODE_CASE.
6. What exceptions and mistakes are most common when working with regular expressions in Java?
What exceptions and mistakes are most common when working with regular expressions in Java?
A pattern is just a string, so almost all mistakes show up only at runtime:
Pattern.compile("\d+") with a single backslash — Java compilation error illegal escape character; you need "\\d+".
Pattern.compile("[a-z") — PatternSyntaxException: Unclosed character class: the pattern syntax is checked when the Pattern is compiled.
matcher.group(), start() or end() before a successful find() or matches() — IllegalStateException: No match found.
In the replacement string of replaceAll(), $ starts a group reference and \ escapes. The replacement "200$" throws IllegalArgumentException: Illegal group reference, and "$200" is read as a reference to group 2 — IndexOutOfBoundsException: No group 2. Pass arbitrary text through Matcher.quoteReplacement().
Matcher m = Pattern.compile("\\d+").matcher("abc123");
// m.group(); // IllegalStateException: No match found
if (m.find()) {
System.out.println(m.group()); // 123
}
System.out.println("Price: 100".replaceAll("100",
Matcher.quoteReplacement("200$"))); // Price: 200$
No exception, but a wrong result: "abc123".matches("\\d+") returns false (you need find()), and nested quantifiers such as (a+)+b cause catastrophic backtracking (ReDoS) on a long string without a match.