If you have a user provided regex that you cannot change, but you still need the rightmost match, wrap the pattern with ^.*( and ) (or [\s\S]* to match across linebreaks) and grab capture group 1 contents:
"^.*(:.*)"
See the regex demo
The thing is that the above pattern matches
^ - the start of string
.* - matches any 0+ characters other than linebreak characters (if you use [\s\S]*, all chars will be matched) as many as possible (because * is a greedy quantifier)
(:.*) - a capturing group that matches : and then any 0+ characters other than linebreak characters.
Note that the first .* will actually grab as many chars as possible, up to the end of the line (and in most cases, it is the end of the string if there are no linebreaks). Then backtracking occurs, the regex engine will start trying to accommodate text for the subsequent subpatterns (here, it will be the user pattern). Thus, the user subpattern that will get captured will be at the rightmost position.
An example (basic) C++ program showing how this can work:
#include <regex>
#include <string>
#include <iostream>
using namespace std;
int main() {
string user_pattern(":.*");
string s("test:55:last");
regex r("^.*(" + user_pattern + ")");
smatch matches;
if (regex_search(s, matches, r)) {
cout<<matches[1].str();
}
return 0;
}
:[^:]+$^.*(:.*)$but it is not that cool.std::regexto analyze the string from right to left (as in .NET).