It looks like this problem . And since you are using PCRE using the recursion syntax, there really is a solution.
/ (?(DEFINE)
The essence of this template is obviously a parenthesized subpattern. Maybe I should think about it. This is the structure:
(normal* (?:special normal*)*)
Where normal is [^()] and special is [(](?P>parenthesized)[)] . This method is called "unrolling-the-loop" . It is used to match what is structured.
nnnsnnsnnnnsnnsnn
Where n corresponds to normal and s corresponds to special .
In this particular case, everything is a little more complicated, because we also use recursion. (?P>parenthesized) recursively uses the parenthesized pattern (which is part). The syntax (?P>...) can be considered as a backlink, except that the engine does not try to match what corresponds to the group ... but instead uses its subformat again.
Also note that my template will not give you an empty string for the correct patterns in brackets, but will fail. You can fix it by leaving a glance. Lookbehind is not really required because the engine will always return the left-most match.
EDIT: Judging by your two examples, you really don't want everything after the last inconsistent bracket, but only up to the first comma. You can use my result and divide by , or try the Czech answer.
Further reading:
EDIT: I noticed that you mentioned in your question that you were using Object Pascal. In this case, you probably are not using PCRE, which means there is no support for recursion. In this case, there cannot be a full regular expression of the problem. If we impose a restriction such as “after the last inconsistent bracket” there can be only one level of nesting (as in all your examples), then we can come up with a solution. Again, I will use "unrolling-the-loop" to match substrings of the form xxx(xxx)xxx(xxx)xxx .
(?<=[(])
If you ever add an input example, for example aaa(xxx(yyy()) , where you want to match xxx(yyy()) , then this approach will not match it. In fact, no regular expression that uses recursion , can handle arbitrary levels of nesting.
Since your regular expression flavor does not support recursion, you are probably better off not using regular expression at all. Even if my last regular expression matches all your current input examples, it is really confusing and maybe not worth the trouble. How about this: go through the string character by character and save a stack of brackets. Then the following pseudo code gives you everything after the last unsurpassed ( :
while you can read another character from the string if that character is "(", push the current position onto the stack if that character is ")", pop a position from the stack
Then, to get everything up to the first unprotected comma, you can continue this result again:
nestingLevel = 0 while you can read another character from the string if that character is "," and nestingLevel == 0, stop if that character is "(" increment nestingLevel if that character is ")" decrement nestingLevel take a substring from the beginning of the string to the position at which you left the loop
These two short cycles will be much easier for any other to understand in the future and much more flexible than a regular solution (at least one without recursion).