Unsatisfiable Regex Lookahead
ID |
java.regex_contradictory_lookahead |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
code-style |
Description
Reports a positive lookahead (?=X) immediately followed by a mandatory character or character class Y, where X starts with a character or class that can never be the same as Y.
Rationale
A lookahead does not consume input, so whatever comes right after it is tested against the same character the lookahead just looked at. If that character would have to be both what X wants and what Y wants, and the two share nothing in common, nothing can ever satisfy both:
Pattern.compile("(?=m)n");
// the character right here must be 'm' (to satisfy the lookahead)
// and 'n' (to satisfy what follows) at the same time - impossible
Remediation
Use a lookbehind instead, so the lookahead’s target and what follows are no longer forced onto the same character; or, if the lookahead was only ever meant to check the start of what follows, drop it — the following atom already says the same thing:
Pattern.compile("(?<=m)n");
Pattern.compile("m(?=n)");
What is not reported
Only the lookahead’s own leading character or class is compared against what follows — not its full body — so (?=mn)mn and (?=mn)mno are not reported: the lookahead’s first character is a prefix of what follows, not a contradiction of it. A lookahead with nothing mandatory right after it (for example at the end of the pattern, as in m(?=n)), a negative lookahead or a lookbehind, and a mandatory atom that is itself quantified, are all out of scope.