Group parts of the regex together to make the intended operator precedence explicit

Viewed 1628

My java code:

String str2 = "\"49110-01-T-GST" + "\"";

And I just want to extract the 49110 out of the above string which has leading and trailing double quotes.

So I am using:

str2.replaceAll("^\"|-.*", "")

Above line solve the purpose but now I get sonar issue which says

Group parts of the regex together to make the intended operator precedence explicit.

Can anyone please fix the sonar issue

2 Answers

Grouping works by surrounding parts of the expression with parentheses.

str2.replaceAll("(^\")|(-.*)", "")

The reason why it's good to make it explicit is because this is also valid:

^(\"|-).*

as well as a lot of other possibilities for grouping. It's not an error to leave the parentheses away but may hinder reading.

Well, Sonar has problems with the ^, because it is part of only the alternative left of the |. Some readers may misunderstand this, and read the pattern as follows:

^(\"|-.*)

Or, in words: "match a start-of-text, followed by either a double-quote or a dash-optionally-followed-by-characters".

Sonar warns about this. Here is their explanation:

In regular expressions, anchors (^, $, \A, \Z and \z) have higher precedence than the | operator. So in a regular expression like ^alt1|alt2|alt3$, alt1 would be anchored to the beginning, alt3 to the end and alt2 wouldn’t be anchored at all. Usually the intended behavior is that all alternatives are anchored at both ends. To achieve this, a non-capturing group should be used around the alternatives.

In cases where it is intended that the anchors only apply to one alternative each, adding (non-capturing) groups around the anchors and the parts that they apply to will make it explicit which parts are anchored and avoid readers misunderstanding the precedence or changing it because they mistakenly assume the precedence was not intended.

Source: https://rules.sonarsource.com/java/RSPEC-5850

You could fix this by using the pattern (^\")|-.* (add ?: to discard the capture group).

However, I would propose to achieve the replacement as follows:

str.replaceAll("^\"(\\d+).*", "$1");
Related