This is because .* First matches the entire string. At this point, it is no longer possible to match 99 , and since the group is optional, the regex engine stops because it found a successful match.
If, on the other hand, a group is required, the regular expression engine should return to .* .
Compare the following debugging sessions from RegexBuddy (the part of the line associated with .* Is highlighted in yellow, the part is (99) blue):
.*(99) :

.*(99)? :

source share