As kcott mentioned, this might be an example of a problem better solved without regex, but since you have indicated a desire to learn, I will explain:
The pattern qr/^.*(\..*)$/ will always backtrack but happens to work (and will continue to work) because of the (documented and stable) order in which the regex engine considers possible matches. This pattern starts at the beginning of the buffer (and only there) /^/, then matches the entire string /.*/, then fails to match the /\./, so the regex engine begins backtracking, removing characters from the greedy qualifier's match until a /\./ matches or the beginning of the string is reached (the match fails if this occurs). After the regex engine has found a position where /\./ can match, the second /.*/ is applied, matching the suffix after the /\./ and completing the capture group. The final /$/ is an assertion that the capture group extends to the end of the string, but is not actually needed because the regex engine will consider that match first and it will succeed. Including the final /$/ is good practice, however, since it clearly indicates the intent to later programmers.
Depending on your input and details of the regex engine implementation, you may be able to get better performance by changing the pattern to qr/(\.[^.]*)$/, which removes the anchor at the start of the string. This pattern first searches for a dot /\./, then matches any (possibly empty) sequence of characters other than dot /[^.]*/ (dot is not special in character classes), then asserts that the end of the string was reached before the match returns success. Again, the engine can backtrack if the string contains multiple dots, but backtracking is avoided in the simple case of input containing only one dot: the regex engine will find the dot, reach the end of the string scanning only non-dot characters, and return success. If the input contains multiple dots, the regex engine will find the first dot /\./, then match characters until the next dot /[^.]*/, then fail the end-of-line assertion /$/ and backtrack to searching for the next dot, which (depending on the regex optimizer) it may already have.
There is another issue here, not always covered in RegEx101: the * qualifier matches zero-or-more, while the + qualifier matches one-or-more, and there are also {N,M} qualifiers for general number ranges. Early regular expression engines did not support the + or {N,M} qualifiers, but Perl's regex engine has both. In an {N,M} qualifier, the upper limit can be omitted for "at least N" and the comma can also be omitted for "exactly N" matches. The {N,M} form is most general: * is equivalent to {0,}, + is equivalent to {1,}, and ? is equivalent to {0,1}, but the shorter single-character forms should always be preferred in hand-written patterns for readability.
For all the details, see perlre and "Regexp Quote-Like Operators" in perlop.
In reply to Re: My regex works, but I want to make sure it's not blind luck
by jcb
in thread My regex works, but I want to make sure it's not blind luck
by SergioQ
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |