Fire Lancer Fire Lancer - 2 months ago 31
C++ Question

C++ reverse regex_search

I am using std::regex and want to find the last position in a string that matches some user defined regular expression string.

For example given the regex

:.*
and the string "test:55:last", I want to find ":last", not ":55:last".

To clarify, as a user provided regex, I just get their regex plus a "reverse" checkbox, so I can alter the regex, but it must be in a programmatic way.

Answer

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;
}