Java Quantifiers are special symbols in Regular Expressions (Regex) that specify how many times a character, character class, or group can occur in a pattern. They make regex more powerful and flexible for tasks such as input validation, searching, parsing, and text manipulation.
- Control the number of occurrences of a pattern.
- Work with characters, character classes, and groups.
public class GFG {
public static void main(String[] args) {
String input = "0007";
System.out.println(input.matches("0*\\d"));
}
}
Output
true
Explanation: 0* matches zero or more occurrences of 0, while \d represents a digit. Therefore, "0007" matches the pattern.
Common Quantifier Symbols Used in Java
These symbols specify how many times a character, character class, or group can occur in a regular expression. They represent the basic quantifier symbols, while their matching behavior can be Greedy, Reluctant, or Possessive.
- X* –> Zero or more occurrences of X
- X? –> Zero or one occurrence of X
- X+ –> One or more occurrences of X
- X{n} –> Exactly n occurrences of X
- X{n,} –> At least n occurrences of X
- X{n,m} –> Between n and m occurrences of X (inclusive)
Here, X can represent a character, character class, or group.
For example:
a{3}
matches:
aaa
Types of Quantifiers in Java Regex
1. Greedy Quantifier
Greedy quantifiers try to match as much input as possible while still allowing the complete regular expression to match. This is the default behavior of quantifiers in Java.
Common greedy quantifiers include:
*
+
?
{n}
{n,}
{n,m}
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GFG {
public static void main(String[] args) {
String input = "<b>Java</b><b>Regex</b>";
Pattern pattern = Pattern.compile("<b>.*</b>");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
Output
<b>Java</b><b>Regex</b>
Explanation The .* part is greedy. It consumes as many characters as possible before allowing the final </b> in the pattern to match. Therefore, the regex matches from the first <b> to the last </b>
2. Reluctant Quantifiers
Reluctant quantifiers, also called lazy quantifiers, try to match as little input as possible while still allowing the complete regex to match. They are created by adding ? after a quantifier.
Examples include:
*?
+?
??
{n}?
{n,}?
{n,m}?
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GFG {
public static void main(String[] args) {
String input = "<b>Java</b><b>Regex</b>";
Pattern pattern = Pattern.compile("<b>.*?</b>");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
Output
<b>Java</b> <b>Regex</b>
Explanation: The .*? part is reluctant. Instead of consuming as much text as possible, it consumes only the minimum number of characters needed to reach the next </b>.
So the matches are:
<b>Java</b>
<b>Regex</b>
instead of:
<b>Java</b><b>Regex</b>
3. Possessive Quantifier
Possessive quantifiers try to match as much input as possible and do not backtrack. They are created by adding + after a quantifier.
Examples include:
*+
++
?+
{n}+
{n,}+
{n,m}+
public class GFG {
public static void main(String[] args) {
System.out.println("aaaa".matches("a+a"));
System.out.println("aaaa".matches("a++a"));
}
}
Output
false
Explanation: a+a returns true because the greedy a+ can backtrack and leave one a for the final a in the pattern. a++a returns false because the possessive a++ consumes all characters and does not allow backtracking.
Greedy vs Reluctant vs Possessive Quantifiers
Aspect | Greedy Quantifiers | Reluctant (Lazy) Quantifiers | Possessive Quantifiers |
|---|---|---|---|
Matching Behaviour | Matches as much as possible while still allowing the overall match | Matches as little as possible to satisfy the pattern | Matches as much as possible without giving up characters |
Backtracking | Allows backtracking | Allows backtracking | Does not allow backtracking |
Syntax / Usage | Default quantifiers (*, +, {m,n}) | Append ? after the quantifier (*?, +?, {m,n}?) | Append + after the quantifier (*+, ++, {m,n}+) |
Control Over Matching | Least control (default behavior) | Highest control over minimal matching | Strictest control, no backtracking |
Performance | Can be slower due to backtracking | Can be slower due to frequent backtracking | Often faster, but may cause match failure |
Common Use Case | General-purpose matching | Precise or minimal matching scenarios | Performance-critical patterns where backtracking is unnecessary |
Advantages of Java Quantifiers
- Simplify Regular Expressions by reducing repetitive pattern definitions.
- Control Repetition using exact, minimum, maximum, or unlimited occurrences.
- Improve Pattern Matching for complex text and input formats.
- Support Input Validation for emails, phone numbers, passwords, and IDs.
- Enhance Readability by making regex patterns shorter and easier to understand.
- Optimize Performance with possessive quantifiers by avoiding unnecessary backtracking.