Redundant Alternation Branch
ID |
php.regex_alternatives_redundant |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Code Smell |
Language |
Php |
Tags |
code-smell, regex |
Description
Reports an alternation branch that can never match anything another branch of the same alternation does not already match.
Three shapes are reported, and only these three, because they are the ones decidable without a general subsumption engine:
-
two branches whose whole content is the same run of plain characters —
(?:ab|ab); -
a single-character branch already covered by a sibling single-character class —
(?:[ab]|a); -
any branch standing beside a
.*or.+sibling, which already matches everything —(?:.*|abc).
Rationale
// Bad
preg_match('/(?:ab|ab)/', $s);
preg_match('/(?:[ab]|a)/', $s);
-
A branch that can never contribute a match is dead weight in the pattern: the engine still tries it on every backtrack, and the reader still has to work out whether it means something.
-
It is normally the residue of an edit — a class was widened and the individual character it replaced was left behind, or a branch was pasted twice.
-
Where the duplication was not intentional, one of the two branches was meant to be something else, and the pattern is quietly not doing what it says.
Remediation
Delete the branch that adds nothing, or fix the one that was meant to differ.
// Good
preg_match('/ab/', $s);
preg_match('/[ab]/', $s);
What is not reported
A redundant-looking branch inside its own capturing group is left alone — /(ab|ab)/. The capturing group is what tells the caller which alternative matched, so the branch is still doing work.
General subsumption is deliberately out of scope: a wrong verdict would delete a branch the author needed. Overlapping quantified branches such as /(?:a+b|ab+)/ are therefore accepted as a false negative. A pattern carrying the x modifier is not analysed, since under it whitespace is not pattern content and branch spans no longer measure what PCRE sees.