Regex Possessive Quantifier Conflict
ID |
java.regex_possessive_quantifier_conflict |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
code-style |
Description
Reports a possessive repetition (X*+, X++, X{n,}+) over a single character or simple class X, immediately followed by a mandatory character or class whose set is already fully covered by X.
Rationale
A possessive quantifier consumes every character it can and never gives any back — unlike a greedy quantifier, it does not backtrack to free one up for what follows. If what follows can only be a character X already claimed, that sub-pattern can never get one:
Pattern.compile("a++a");
// the possessive '+' eats every 'a' in the run; the trailing 'a' never gets one
Pattern.compile("\\d*+[02468]");
// '\d*+' eats every digit, so an even digit right after it never gets one either
Remediation
Give the following sub-pattern back a character to work with — split off one repetition, or use a greedy quantifier where backtracking is actually wanted:
Pattern.compile("aa++bc"); // the possessive body no longer overlaps what follows
Pattern.compile("\\d*+(?<=[02468])"); // a lookbehind consumes nothing, so there is no conflict
What is not reported
Only the atom immediately touching the quantifier on each side is examined. aa++bc is compliant: the possessive quantifier’s own body is just the second a, and b was never something it could have consumed — the first a, one position further back, does not enter into this rule’s local check. A lookbehind right after the quantifier consumes nothing and is compliant for the same reason. Greedy and reluctant quantifiers are out of scope; only possessive ones are checked.