Regex Anchor Precedence

ID

java.regex_anchor_precedence

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

code-style

Description

Reports an alternation whose first branch starts with ^/\A or whose last branch ends with $/\Z/\z, while at least one other branch of the same alternation carries no such anchor.

Rationale

Anchors bind tighter than |, so ^a|b|c$ is not "match a, b or c, anchored at both ends" — it parses as (^a)|b|(c$):

Pattern.compile("^a|b|c$");
// "a" only matches at the very start, "c" only at the very end,
// but "b" matches anywhere in the input

The layout suggests every branch is bounded; only the outermost ones actually are.

Remediation

Wrap the alternatives in a non-capturing group so the anchors apply to the whole thing, or repeat the anchors on every branch if each was really meant to be anchored on its own:

Pattern.compile("^(?:a|b|c)$");
// or
Pattern.compile("^a$|^b$|^c$");

What is not reported

An alternation where every branch carries the same anchor on its own (a$|b$|^c$) is not reported — there is no gap between branches to be misled by. An alternation already wrapped in a group (^(?:a|b|c)$), or one whose anchored branches are each explicitly scoped in their own group ((?:^a)|b|(?:c$)), reads exactly as intended and is not reported either. An alternation with no anchor at either end is out of scope.

© 2026 Xygeni. All rights reserved